Heroku: dodatki, logi i monitorowanie

Paweł Ćwik

Zaktualizowaliśmy ten tekst dla Ciebie!
Data aktualizacji: 31.12.2024
Autor aktualizacji: Marcin Majgier

W poprzednim artykule wprowadziłem Cię w podstawy Heroku i pokazałem, jak wdrożyć aplikację Spring Boot. W drugiej części pokażę, jak dodać obsługę bazy danych, przyjrzeć się logom oraz metrykom naszej aplikacji.

Heroku oferuje system dodatków, który pozwala na integrację dodatkowych usług z aplikacją, takich jak bazy danych, kolejki komunikatów (message brokers), systemy buforowania (cache), magazyn danych, usługi e-mail i wiele innych.

Dodatki te są dostarczane najczęściej przez zewnętrznych dostawców, ich szeroki wybór można znaleźć na stronie Heroku Marketplace.

Dodawanie wsparcia dla bazy danych do aplikacji na Heroku

Mimo, że PostgreSQL nie jest już dostępny za darmo, wciąż pozostaje niedrogim rozwiązaniem, pozwalającym na łatwe “podpięcie” bazy danych do naszego projektu. Koszt podstawowego plany zaczyna się od 0.007$ za godzinę (czyli około 5$ miesięcznie). Aby dodać obsługę baz danych, możesz skorzystać z dwóch opcji, pierwszą jest interfejs web, w którym należy wyszukać PostgreSQL i po wybraniu “PostgreSQL in Heroku” kliknąć “Install Heroku Postgres”.

Alternatywnie można użyć linii polece (CLI) i wykonać komendę:

heroku addons:create heroku-postgresql:essential-0

Po uruchomieniu pojawi się informacja podobna to poniższej:

Creating heroku-postgresql:essential-0 on ⬢ sheltered-beach-59560... ~$0.007/hour (max $5/month)
Database should be available soon
postgresql-regular-38138 is being created in the background. The app will restart when complete...
Use heroku addons:info postgresql-regular-38138 to check creation progress
Use heroku addons:docs heroku-postgresql to view documentation
MacBook-Pro-majgierm:heroku-demo marcin$ heroku addons:info postgresql-regular-38138
=== postgresql-regular-38138

Po zakoczeniu instalacji baza danych będzie gotowa do użycia. Następnie należy skonfigurować aplikację, korzystając z odpowiedniego adresu URL bazy danych:

heroku config

Polecenie wyświetli adres URL bazy danych, który będzie wyglądał podobnie do poniższego:

postgres://qamtrwcghvuzfm:e5cc937842c248126e9dba…@c8m0261h0c7ik.cluster-czrs8kj4isg7.us-east-1.rds.amazonaws.com:5432/d958kfmhjqnnh6

Bez obaw, nie ma potrzeby go przepisywać/kopiować. Poźniej pokażę, jak skonfigurować ustawienia bazy w naszej aplikacji. Na razie skupmy się na przygotowaniu kodu naszej aplikacji.

Rozszerzenie naszej aplikacji

Zacznijmy od rozszerzenia przykładu z poprzedniego artykułu o te trzy zależności::

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.4</version>
</dependency>

Pierwsza zeleżność spring-boot-starter-data-jpa pozwala nam użyć biblioteki Spring Data i jej repozytoriów. Kolejna spring-boot-starter-data-rest udosrępnia repozytoria jako interfejsy REST w naszej aplikacji. Ostatnia z zależności jest to sterownik JDBC bazy PostgreSQL.

Stwórzmy jeszcze encję Person:

package com.jlabs.heroku_demo;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    private Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}


Mając już tą klasę, możemy utworzyć repozytorium spring-data bazy danych:

package com.jlabs.heroku_demo;

import org.springframework.data.repository.CrudRepository;

public interface PeopleRepository extends CrudRepository<Person, Long> {
}

Musimy jeszcze rozszerzyć nasz controller a poprzedniego artykułu oraz szablon thymeleaf tak, żeby możliwe było użycie nowych danych:

package com.jlabs.heroku_demo;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {

    private final PeopleRepository peopleRepository;

    public HelloController(PeopleRepository peopleRepository) {
        this.peopleRepository = peopleRepository;
    }

    @RequestMapping("hi")
    public String hello(Model model) {
        model.addAttribute("people", peopleRepository.findAll());
        return "hello";
    }
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Clockwork Java Hello</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
        <p th:each="person : ${people}" th:text="${person.name}"/>
    </body>
</html>

Ustawienia bazy danych w aplikacji

Pozostaje jeszcze konfiguracja bazy w pliku application.properties::

Spring.datasource.url=${JDBC_DATABASE_URL}
spring.datasource.username=${JDBC_DATABASE_USERNAME}
spring.datasource.password=${JDBC_DATABASE_PASSWORD}
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

Zapewne zauważyłeś odniesienia do zmiennych środowiskowych takich jak:  JDBC_DATABASE_URL. Wyjaśnijmy o co z nimi chodzi.

Dyno Heroku (kontener Unix, w którym działa nasza aplikacja) udostępnia zmienne środowiskowe zawierające dane uwierzytelniające, adresy, porty oraz inne szczegóły konfiguracyjne dotyczące naszych dodatków. Oznacza to, że nie musimy na stałe wpisywać w kodzie adresu URL JDBC dostarczonego przez heroku config, zamiast tego możemy korzystać z dostarczonych zmiennych systemowych. 

Teraz wdróżmy naszą amodyfikowaną aplikację (git commit; heroku login; git push heroku master) i przejdźmy na: https://sheltered-beach-59560-21a465b93ca9.herokuapp.com. 

Powinieneś zobaczyś informacje odnosnie endpointów REST podobnych do tych poniżej: 

{
  „_links”: {
    „persons”: {
      „href”: „https://sheltered-beach-59560-21a465b93ca9.herokuapp.com/persons”
    },
    „profile”: {
      „href”: „https://sheltered-beach-59560-21a465b93ca9.herokuapp.com/profile”
    }
  }
}
}

Now use curl, postman or any other tool to call POST requests to https://sheltered-beach-59560-21a465b93ca9.herokuapp.com/persons endpoint and persist some data. In curl it can be like below:

curl -X POST https://sheltered-beach-59560-21a465b93ca9.herokuapp.com/persons \

-H „Content-Type: application/json” \

-d '{ „name”: „John” }’

Teraz jak odwiedzimy stronę:  https://sheltered-beach-59560-21a465b93ca9.herokuapp.com/hi to wyświetlona zostanie lista dodanych osób.

To jest to! W kilku prostych krokach dodaliśmy właśnie obsługę bazy danych do naszej aplikacji w chmurze.

Logs

Heroku zapewnia prosty dostęp do logów z poziomu linii poleceń:
heroku logs

2024-12-30T15:48:38.267743+00:00 heroku[router]: at=info method=HEAD path=”/” host=sheltered-beach-59560-21a465b93ca9.herokuapp.com request_id=0dc97b17-9019-4737-9612-c48578f1b9f2 fwd=”104.47.51.254″ dyno=web.1 connect=0ms service=58ms status=204 bytes=162 protocol=https

2024-12-30T15:50:39.571169+00:00 heroku[router]: at=info method=POST path=”/persons” host=sheltered-beach-59560-21a465b93ca9.herokuapp.com request_id=57fffa5b-e03c-4cf0-a446-f923d8324ac1 fwd=”83.10.27.53″ dyno=web.1 connect=0ms service=148ms status=201 bytes=569 protocol=https

2024-12-30T15:52:25.041531+00:00 app[web.1]: Hibernate: select p1_0.id,p1_0.name from person p1_0

2024-12-30T15:52:25.301385+00:00 heroku[router]: at=info method=GET path=”/hi” host=sheltered-beach-59560-21a465b93ca9.herokuapp.com request_id=2efe269c-7b37-4ef5-9519-026841d48dba fwd=”52.123.138.164″ dyno=web.1 connect=0ms service=343ms status=200 bytes=374 protocol=https

2024-12-30T15:52:26.566648+00:00 app[web.1]: Hibernate: select p1_0.id,p1_0.name from person p1_0

Każdy wpis w logach ma ten sam format: znacznik czasu źródło[dyno]: wiadomość. Podczas gdy znacznik czasu i wiadomość są oczywiste, części source i dyno są specyficzne dla Heroku. 

Source określa, czy log pochodzi z jednego z naszych dyno — wtedy jest oznaczony jako „app”, czy z komponentu systemowego Heroku (np. router HTTP lub menedżer dyno), w takim przypadku źródło to „heroku”. 

Dyno to nazwa komponentu dyno, który zapisał linię loga (np. web.1), lub w przypadku komponentów systemowych Heroku — „router” lub „manager”. 

Możemy zastosować filtry do logów, aby wyświetlić wpisy z określonego źródła, określonego dyno lub obu jednocześnie, używając argumentów –source (lub -s) oraz –dyno (lub -d).

heroku logs –dyno web.1
heroku logs –source heroku

You can also combine the filtering switches with –tail to get a real-time stream of filtered output.

heroku logs –source app –tail

Polecenie logs domyślnie pobiera 100 linii logów. Możesz określić liczbę linii logów do pobrania (maksymalnie 1500) za pomocą opcji –num (lub -n).

heroku logs -n 200

Metryki

Ponieważ wszystkie plany Heroku są teraz płatne, mamy dostęp do podstawowych metryk bezpośrednio z poziomu panelu Heroku. Metryki te obejmują:

  • Użycie pamięci przez naszą aplikację
  • Średni czas odpowiedzi
  • Ilość żąda na minutę

W planie Eco wszystkie metryki są dostępne z rozdzielczością 24-godzinną, co pozwala uzyskać wgląd w wydajność aplikacji i zidentyfikować potencjalne problemy związane z jej działaniem. W wyższych planach (Standard lub wyższych) dostępne są dodatkowe opcje dotyczące rozdzielczości czasowej, a także możliwość ustawiania progów alertów, np. powiadomień o wysokich czasach odpowiedzi lub zużyciu pamięci, co umożliwia sprawne zarządzanie wydajnością aplikacji.

Podsumowanie

W tym artykule dodaliśmy do naszej aplikacji obsługę bazy danych PostgreSQL, pokazaliśmy również podstawowe komendy do pobierania i przeglądania logów oraz metryki, które ułatwiają monitorowanie aplikacji. 

Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!

Skontaktuj się z nami