Wiecie już jak uruchomić monitoring aplikacji w 10 minut. Jeśli nie wiecie, to zdecydowanie nadróbcie zaległości. Tylko jak to się stało, że bez dodania linijki kodu dostaliśmy tyle dobrego? Chcemy również zapoznać Was z podstawowymi abstrakcjami Micrometer i rozwiać mgłę tajemnicy dotyczącą jego integracji ze Spring Boot. Jak to się stało, że po dodaniu jednej zależności otrzymaliśmy gotowy do użycia endpoint wypełniony metrykami dla Prometheus’a. Magia czy konwencje? Zobaczymy.
Jednak zanim wyruszymy w naszą podróż, wybierzemy sobie jednego bohatera, a raczej bohaterkę – metrykę. Będzie ona towarzyszyła nam podczas zgłębiania ścieżek integracji Micrometer’a i Spring’a. Niech będzie to:
system_cpu_usage
Teraz już wszystko gotowe – rozpoczynamy.
Spring Boot Actuator
O module spring-boot-actuator
będziemy pisać pewnie jeszcze nie raz. Dostarcza on wiele funkcjonalności niezbędnych dla produkcyjnej aplikacji. Skupimy się jednak teraz na systemie metryk.
Jest jedna rzecz, o której warto wspomnieć. Nawet jeśli nie dodalibyśmy zależności do Prometheus’a metryki aplikacji już by na Ciebie czekały. Zanim ruszysz dalej, dociągnij najnowszą wersję repozytorium metrics-ready-sandbox-app. Jest tam jedna zmiana dotycząca dostępnych endpointów Actuatora.
Uruchom aplikację i odwiedź w przeglądarce adres
http://localhost:8080/actuator
Widzimy tam kilka linków, a wsród nich
{
"_links": {
...
"prometheus": {
"href": "http://localhost:8080/actuator/prometheus",
"templated": false
},
"metrics-requiredMetricName": {
"href": "http://localhost:8080/actuator/metrics/{requiredMetricName}",
"templated": true
},
"metrics": {
"href": "http://localhost:8080/actuator/metrics",
"templated": false
}
}
}
Zobaczmy teraz listę dostępnych metryk
http://localhost:8080/metrics
{
"names": [
...
"system.cpu.count",
"system.cpu.usage",
"system.load.average.1m"
]
}
I podejrzyjmy jakie dane zawiera nasza metryka:
http://localhost:8080/actuator/metrics/system.cpu.usage
{
"name": "system.cpu.usage",
"description": "The \"recent cpu usage\" for the whole system",
"baseUnit": null,
"measurements": [
{
"statistic": "VALUE",
"value": 0.4
}
],
"availableTags": []
}
Tę samą metrykę możemy zobaczyć również pod adresem wystawionym dla Prometheus’a
http://localhost:8080/actuator/prometheus
# HELP system_cpu_usage The "recent cpu usage" for the whole system
# TYPE system_cpu_usage gauge
system_cpu_usage 0.4
Wszystko działa jak należy, ale jak to się stało 🙂 ? Zaczniemy od wyszukania klasy odpowiedzialnej za generowanie widoku metryk w Actuatorze – MetricsEndpoint. Jedynym polem tej klasy jest registry
typu MeterRegistry, ale to już inna zależność. Zanurzymy się w tej chwili w świat Micrometer’a.
Rejestr Metryk
Otwórzmy w IDE klasę MeterRegistry. Jest to jedna z kluczowych abstrakcji Micrometer’a. Miejsce odpowiedzialne za zbieranie i przechowywanie metryk. Posiada kilka implementacji. Opiszę tutaj te najczęściej używane.
SimpleMeterRegistry
– wersja „podstawowa”, to ta implementacja jest dostępna domyślnie w Actuatorze, jeśli nie zdecydujemy inaczej.
CompositeMeterRegistry
– jeśli z jakiegokolwiek powodu potrzebujesz wysyłać metryki do więcej niż jednego systemu metryk to, to jest miejsce, do którego zdecydowanie musisz zajrzeć.
PushMeterRegistry
– w przypadku, gdy Twój system metryk działa w trybie push (np AppOptics, Azure Monitor, Datadog, Influx, New Relic, SignalFx), będziesz musiał zaimplementować lub dorzucić zależność implementującą tę klasę abstrakcyjną.
Jedna notka dotycząca dorzucania zależności. Dodaliśmy micrometer-registry-prometheus
. Zobaczmy czy możemy znaleźć coś ciekawego w jej wnętrzu.
PrometheusMeterRegistry
– jak się okazuje, znajdziemy tutaj kolejną implementację MeterRegistry
, dostosowaną do konwencji Prometheus’a.
Warto również zajrzeć do listy dostępnych implementacji rejestru. W tej chwili znajduje się na niej ponad 20 gotowych do użycia systemów metryk. Obejmują one też chmurowe rozwiązania, takie jak Azure Monitor czy AWS CloudWatch.

Poznaliśmy pierwszą z podstawowych abstrakcji Micrometer’a. Nadal nie mamy odpowiedzi na wszystkie pytania. Jak to się dzieje, że wystarczy dodanie zależności i już automatycznie mamy dostępne metryki dla Prometheus’a. Słowem klucz jest tu automatycznie.
Spring Boot Actuator Autoconfigure
Wracamy do Spring’a, a dokładniej do spring-boot-actuator-autoconfigure. Pierwszy styk integracji Micrometer i Spring Boot. Zobaczymy, że nic nie dzieje się tutaj magicznie, a jest to nadal zwykły kod.
Automatyczny wybór rejestru metryk
Zajrzyjcie do klasy PrometheusMetricsExportAutoConfiguration
. Widzimy tam kilka adnotacji, a wśród nich @AutoConfigureBefore oraz @AutoConfigureAfter. Są to adnotacje służące do sterowania kolejnością konfiguracji. Jeśli ruszymy ich śladem, odkryjemy następującą ścieżkę:

W naszym przypadku automatyczna konfiguracja kończy się na PrometheusMetricsExportAutoConfiguration
. W kroku 3, czyli SimpleMetricsExportAutoConfiguration
widzimy warunek
@ConditionalOnMissingBean({MeterRegistry.class})
Bean ten został już stworzony w kroku 2. Pierwsza zagadka została rozwiązana – mamy skonfigurowany Prometheus’owy rejestr metryk. To nie koniec. W dalszym ciągu nie wiemy, w jakis sposób pojawił się gotowy do użycia endpoint z metrykami.
Automatyczne włączenie endpointu Prometheus’a
Jeśli coś jest robione automatycznie w przypadku Actuator’a, to od razu wiadomo, gdzie musimy zajrzeć. Wyszukujemy klasę PrometheusMetricsExportAutoConfiguration
z zależności spring-boot-actuator-autoconfigure
. Widzimy, że zostanie ona użyta, tylko jeśli spełniony jest warunek
@ConditionalOnClass({PrometheusMeterRegistry.class})
W naszym przypadku jest on oczywiście spełniony. Zatem PrometheusScrapeEndpoint
, który czeka na nas gotowy do włączenia w Actuatorze, zostaje udostępniony. Zagadka nr 2 – rozwiązana. Warto zwrócić uwagę, że endpoint ten dba o przygotowanie odpowiedzi zgodnej ze schematem Prometheus’a za nas.
Dodawanie metryk do rejestru
Zaszliśmy już dość daleko. Wiemy, czemu endpoint z metrykami Prometheus’a został udostępniony po dodaniu zależności. Wiemy też jaki obiekt przechowuje nasze metryki. Nie wiemy tylko w jaki sposób nasza wybrana metryka tam wylądowała.
Micrometer Binder
Przyszedł czas na poznanie kolejnej abstrakcji z Micrometer’a – Meter Binder. To prosty interfejs z jedną metodą
void bindTo(@NonNull MeterRegistry var1);
Dzięki niemu metryki lądują do właściwego Rejestru. Możemy skorzystać z wielu gotowych do użycia Binder’ów lub też tworzyć własne.
Autokonfiguracja Binder’ów
Drugi styk integracji Micrometer i Spring Boot. Podobnie jak w przypadku Rejestru zaglądamy do spring-boot-actuator-autoconfigure. Znajdziemy tam szereg klas w pakiecie metrics odpowiedzialnych za tworzenie odpowiednich beanów typu MeterBinder
np SystemMetricsAutoConfiguration
. To krok pierwszy – tworzenie Beanów. Krokiem drugim jest zbindowanie ich do wcześniej stworzonego Rejestru.
Zaglądamy zatem ponownie do klasy MetricsAutoConfiguration
i widzimy tam metodę meterRegistryPostProcessor
, która odpowiedzialna jest m.in za zebranie dostępnych Binder’ów i dorzucenie ich do Rejestru.
@Bean
public static MeterRegistryPostProcessor meterRegistryPostProcessor (
ObjectProvider<MeterBinder> meterBinders,
ObjectProvider<MeterFilter> meterFilters,
ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,
ObjectProvider<MetricsProperties> metricsProperties,
ApplicationContext applicationContext) {
return new MeterRegistryPostProcessor(
meterBinders,
meterFilters,
meterRegistryCustomizers,
metricsProperties,
applicationContext);
}

Metryka Micrometer
Wracamy do naszej metryki. Po podejrzeniu hierarchii interfejsu MeterBinder
docieramy do ProcessorMetrics
i naszym oczom ukazuje się kod odpowiedzialny za dodawanie poszukiwanej metryki.
Gauge.builder("system.cpu.usage", this.operatingSystemBean,
(x) -> { return this.invoke(this.systemCpuUsage); })
.tags(this.tags)
.description("The \"recent cpu usage\" for the whole system")
.register(registry);
Tadam – mamy komplet. Szczegóły dotyczące typów metryk, ich konfiguracji umieścimy w najbliższym wpisie. Możemy cieszyć się z rozwikłania zagadki automatycznej konfiguracji metryk.
# HELP system_cpu_usage The "recent cpu usage" for the whole system
# TYPE system_cpu_usage gauge
system_cpu_usage 0.4
Na zakończenie uproszczony schemat integracji Spring Boot i Micrometer.

Podsumowanie
Przeszliśmy dzisiaj dość długą drogę, poznając podstawowe abstrakcje Micrometer’a, ale również jak działa jego integracja (magia) ze Spring’iem. Wystawienie metryk w 10 minut jest możliwe, ale oczywiście tylko dzięki temu, że duża część pracy została za nas przygotowana wcześniej.
Słów parę odnośnie Springa i kolejnej odwiecznej wojny w świecie IT. Wydaje mi się, że należy traktować Spring’a jako narzędzie i dopóki jest ono odpowiednie do rozwiązywanego problemu, po prostu należy z niego skorzystać. Jeśli jednak z jakiegoś powodu nie spełnia on wymagań, można obyć się bez niego. Zachęcam jednak jak w przypadku każdego narzędzia do głębszego zapoznania się z zasadami jego działania. Wtedy „magia” może przestać być „magią”, a przynajmniej nie będzie już tak straszną.
Mam jeszcze jedno pytanko. Czy podobają się Wam wpisy typu Deep Dive? Takie, gdzie staramy się wyjaśnić bardziej szczegółowo, jak działają używane przez nas na co dzień rozwiązania? Nauka kodu poprzez przeglądanie i poznawanie rozwiązań twórców jest chyba jedną z najlepszych form nauki. Ale dajcie znać czy tego typu wpisy są ciekawe.
To tyle na dziś, a już niedługo postaramy się zapoznać was z typami metryk i pokażemy jak stworzyć swoją własną. Stamtąd już tylko krok do zwiększenia Observability Waszego kodu i monitorowania najbardziej krytycznych miejsc systemu – zarówno pod kątem technicznym jak i biznesowym.
Kolejny bardzo fajny i przystępnie napisany artykuł – powodzenia chłopaki 🙂
Dzięki bardzo Łukasz 🙂
Jako anty-fan springa rad jestem z tego wpisu 😀
🙂 Jak zawsze przy ideologiach każda strona znajdzie potwierdzenie swoich racji. Mam jednak nadzieję, że mimo wszystko nieco magii zostało rozwiane. Pozdrawiam Damian
Deep Dive <3 Tylko i wyłącznie.