Metriky pre vaše jarné REST API

ODPOČINOK Najlepšie

Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:

>> SKONTROLUJTE KURZ

1. Prehľad

V tomto výučbe sa začleníme základné metriky do jarného REST API.

Metrickú funkcionalitu zostavíme najskôr pomocou jednoduchých filtrov servletov a potom pomocou Spring Boot Actuator.

2. The web.xml

Začnime registráciou filtra - “MetricFilter" - do web.xml našej aplikácie:

 metricFilter org.baeldung.web.metric.MetricFilter metricFilter / * 

Všimnite si, ako mapujeme filter tak, aby pokrýval všetky prichádzajúce žiadosti - “/*” - ktorý je samozrejme plne konfigurovateľný.

3. Servletový filter

Teraz - vytvorme si náš vlastný filter:

verejná trieda MetricFilter implementuje filter {private MetricService metricService; @Override public void init (konfigurácia FilterConfig) hodí ServletException {metricService = (MetricService) WebApplicationContextUtils .getRequiredWebApplicationContext (config.getServletContext ()) .getBean ("metricService"); } @Override public void doFilter (požiadavka ServletRequest, odpoveď ServletResponse, reťazec FilterChain) hodí java.io.IOException, ServletException {HttpServletRequest httpRequest = ((HttpServletRequest) požiadavka); Reťazec req = httpRequest.getMethod () + "" + httpRequest.getRequestURI (); chain.doFilter (požiadavka, odpoveď); int status = (((HttpServletResponse) odpoveď) .getStatus (); metricService.increaseCount (požiadavka, stav); }}

Pretože filter nie je štandardná fazuľa, nebudeme injektovať metricService ale namiesto toho ich načítajte manuálne - prostredníctvom ServletContext.

Upozorňujeme tiež, že vo vykonávaní reťazca filtra pokračujeme volaním znaku doFilter API tu.

4. Metrika - Počet stavových kódov

Ďalej - poďme sa pozrieť na naše jednoduché MetricService:

@ Verejná trieda služby MetricService {private ConcurrentMap statusMetric; public MetricService () {statusMetric = new ConcurrentHashMap (); } public void increaseCount (požiadavka na reťazec, stav int) {Integer statusCount = statusMetric.get (stav); if (statusCount == null) {statusMetric.put (status, 1); } else {statusMetric.put (status, statusCount + 1); }} verejna mapa getStatusMetric () {return statusMetric; }}

Používame pamäť ConcurrentMap na udržanie počtu pre každý typ stavového kódu HTTP.

Teraz - na zobrazenie tejto základnej metriky - ju namapujeme na a Kontrolór metóda:

@RequestMapping (value = "/ status-metric", method = RequestMethod.GET) @ResponseBody verejná mapa getStatusMetric () {return metricService.getStatusMetric (); }

A tu je ukážka odpovede:

{ "404":1, "200":6, "409":1 }

5. Metrika - stavové kódy na požiadanie

Ďalšie - zaznamenajme metriky pre Počty na požiadanie:

@Service verejná trieda MetricService {súkromná ConcurrentMap metricMap; public void increaseCount (požiadavka na reťazec, stav int) {ConcurrentHashMap statusMap = metricMap.get (požiadavka); if (statusMap == null) {statusMap = new ConcurrentHashMap (); } Počet celých čísel = statusMap.get (status); if (count == null) {count = 1; } else {count ++; } statusMap.put (stav, počet); metricMap.put (požiadavka, statusMap); } verejná mapa getFullMetric () {návrat metricMap; }}

Výsledky metrík zobrazíme pomocou rozhrania API:

@RequestMapping (value = "/ metric", method = RequestMethod.GET) @ResponseBody public Map getMetric () {return metricService.getFullMetric (); }

Takto vyzerajú tieto metriky:

{"GET / users": {"200": 6, "409": 1}, "GET / users / 1": {"404": 1}}

Podľa vyššie uvedeného príkladu malo API nasledujúcu aktivitu:

  • „7“ požiadaviek na „ZÍSKAŤ / používateľov
  • „6“ z nich malo za následok „200“ odpovedí na stavové kódy a iba jedna z „409“

6. Metrické údaje - časové rady

Celkové počty sú v aplikácii trochu užitočné, ale ak systém beží už značnú dobu - je ťažké povedať, čo tieto metriky vlastne znamenajú.

Aby údaje mali zmysel a boli ľahko interpretovateľné, potrebujete časový kontext.

Poďme si teraz vytvoriť jednoduchú metriku založenú na čase; budeme viesť záznamy o počte stavových kódov za minútu - takto:

@Service verejná trieda MetricService {súkromná ConcurrentMap timeMap; private static SimpleDateFormat dateFormat = new SimpleDateFormat ("rrrr-MM-dd HH: mm"); public void increaseCount (požiadavka na reťazec, stav int) {čas reťazca = dateFormat.format (nový dátum ()); ConcurrentHashMap statusMap = timeMap.get (čas); if (statusMap == null) {statusMap = new ConcurrentHashMap (); } Počet celých čísel = statusMap.get (status); if (count == null) {count = 1; } else {count ++; } statusMap.put (stav, počet); timeMap.put (time, statusMap); }}

A getGraphData ():

public Object [] [] getGraphData () {int colCount = statusMetric.keySet (). size () + 1; Nastaviť allStatus = statusMetric.keySet (); int rowCount = timeMap.keySet (). size () + 1; Object [] [] result = new Object [rowCount] [colCount]; výsledok [0] [0] = "Čas"; int j = 1; for (int status: allStatus) {result [0] [j] = status; j ++; } int i = 1; ConcurrentMap tempMap; pre (Vstup entry: timeMap.entrySet ()) {result [i] [0] = entry.getKey (); tempMap = entry.getValue (); for (j = 1; j <colCount; j ++) {result [i] [j] = tempMap.get (result [0] [j]); if (výsledok [i] [j] == null) {výsledok [i] [j] = 0; }} i ++; } vrátiť výsledok; }

Teraz to namapujeme na API:

@RequestMapping (value = "/ metric-graph-data", method = RequestMethod.GET) @ResponseBody public Object [] [] getMetricData () {return metricService.getGraphData (); }

A nakoniec - vykreslíme to pomocou grafov Google:

  Metrický graf google.load ("vizualizácia", "1", {balíčky: ["corechart"]}); function drawChart () {$ .get ("/ metric-graph-data", function (mydata) {var data = google.visualization.arrayToDataTable (mydata); var options = {title: 'Website Metric', hAxis: {title : 'Time', titleTextStyle: {color: '# 333'}}, vAxis: {minValue: 0}}; var chart = new google.visualization.AreaChart (document.getElementById ('chart_div')); chart.draw ( údaje, možnosti);}); } 

7. Používanie ovládača Spring Boot 1.x.

V nasledujúcich niekoľkých častiach sa chystáme zapojiť do funkčnosti aktuátora v Spring Boot, aby sme predstavili naše metriky.

Najprv - budeme musieť pridať závislosť aktuátora na našu pom.xml:

 org.springframework.boot spring-boot-starter-aktuator 

7.1. The MetricFilter

Ďalej - môžeme otočiť MetricFilter - do skutočnej jarnej fazule:

@ Verejná zložka komponentu MetricFilter implementuje filter {@Autowired private MetricService metricService; @Override public void doFilter (požiadavka ServletRequest, odpoveď ServletResponse, reťazec FilterChain) hodí java.io.IOException, ServletException {chain.doFilter (požiadavka, odpoveď); int status = (((HttpServletResponse) odpoveď) .getStatus (); metricService.increaseCount (stav); }}

Toto je samozrejme malé zjednodušenie - ale stojí za to, aby ste sa zbavili predtým manuálneho prepojenia závislostí.

7.2. Použitím CounterService

Poďme teraz použiť CounterService počítať výskyty pre každý stavový kód:

@ Verejná trieda služieb MetricService {@Autowired private CounterService counter; private List statusList; public void increaseCount (int status) {counter.increment ("status." + status); if (! statusList.contains ("counter.status." + status)) {statusList.add ("counter.status." + status); }}}

7.3. Export metrík pomocou Metrické úložisko

Ďalej - musíme exportovať metriky - pomocou Metrické úložisko:

@ Verejná trieda služieb MetricService {@Autowired private MetricRepository repo; súkromný zoznam statusMetric; private List statusList; @Scheduled (fixedDelay = 60000) private void exportMetrics () {metrická metrika; ArrayList statusCount = nový ArrayList (); pre (Stav reťazca: statusList) {metrika = repo.findOne (stav); if (metric! = null) {statusCount.add (metric.getValue (). intValue ()); repo.reset (stav); } else {statusCount.add (0); }} statusMetric.add (statusCount); }}

Upozorňujeme, že ukladáme počty stavové kódy za minútu.

7.4. Jarná topánka PublicMetrics

Môžeme použiť aj Spring Boot PublicMetrics namiesto použitia našich vlastných filtrov exportovať metriky - takto:

Najskôr máme naplánovanú úlohu export metrík za minútu:

@Autowired private MetricReaderPublicMetrics publicMetrics; súkromný zoznam statusMetricsByMinute; private List statusList; private static final SimpleDateFormat dateFormat = nový SimpleDateFormat ("rrrr-MM-dd HH: mm"); @Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList lastMinuteStatuses = initializeStatuses (statusList.size ()); pre (Metric counterMetric: publicMetrics.metrics ()) {updateMetrics (counterMetric, lastMinuteStatuses); } statusMetricsByMinute.add (lastMinuteStatuses); }

Samozrejme musíme inicializovať zoznam stavových kódov HTTP:

private ArrayList initializeStatuses (int size) {ArrayList counterList = new ArrayList (); pre (int i = 0; i <veľkosť; i ++) {counterList.add (0); } return counterList; }

A potom budeme metriky skutočne aktualizovať pomocou počet stavových kódov:

private void updateMetrics (Metrický counterMetric, ArrayList statusCount) {Stav reťazca = ""; int index = -1; int oldCount = 0; if (counterMetric.getName (). contains ("counter.status.")) {status = counterMetric.getName (). podreťazec (15, 18); // príklad 404, 200 appendStatusIfNotExist (status, statusCount); index = statusList.indexOf (stav); oldCount = statusCount.get (index) == null? 0: statusCount.get (index); statusCount.set (index, counterMetric.getValue (). intValue () + oldCount); }} private void appendStatusIfNotExist (stav reťazca, ArrayList statusCount) {if (! statusList.contains (status)) {statusList.add (status); statusCount.add (0); }}

Poznač si to:

  • PublicMetics názov počítadla stavu začať s „kontr.status" napríklad "counter.status.200.root
  • V našom zozname evidujeme počet stavov za minútu statusMetricsByMinute

Naše zhromaždené údaje môžeme exportovať a nakresliť ich v grafe - nasledovne:

public Object [] [] getGraphData () {Dátum aktuálny = nový Dátum (); int colCount = statusList.size () + 1; int rowCount = statusMetricsByMinute.size () + 1; Object [] [] result = new Object [rowCount] [colCount]; výsledok [0] [0] = "Čas"; int j = 1; for (String status: statusList) {result [0] [j] = status; j ++; } for (int i = 1; i <rowCount; i ++) {result [i] [0] = dateFormat.format (new Date (current.getTime () - (60000 * (rowCount - i))))); } Zoznam minútových stavov; Zoznam posledný = nový ArrayList (); pre (int i = 1; i <rowCount; i ++) {minuteOfStatuses = statusMetricsByMinute.get (i - 1); pre (j = 1; j = j? last.get (j - 1): 0); } while (j <colCount) {result [i] [j] = 0; j ++; } last = minuteOfStatuses; } vrátiť výsledok; }

7.5. Nakreslite graf pomocou metrík

Na záver - poďme tieto metriky predstaviť prostredníctvom dvojrozmerného poľa - aby sme ich potom mohli vytvoriť v grafoch:

public Object [] [] getGraphData () {Dátum aktuálny = nový Dátum (); int colCount = statusList.size () + 1; int rowCount = statusMetric.size () + 1; Object [] [] result = new Object [rowCount] [colCount]; výsledok [0] [0] = "Čas"; int j = 1; for (String status: statusList) {result [0] [j] = status; j ++; } Teplota poľa; pre (int i = 1; i <rowCount; i ++) {temp = statusMetric.get (i - 1); výsledok [i] [0] = dateFormat.format (nový dátum (current.getTime () - (60000 * (rowCount - i))))); pre (j = 1; j <= temp.size (); j ++) {výsledok [i] [j] = temp.get (j - 1); } while (j <colCount) {result [i] [j] = 0; j ++; }} vrátiť výsledok; }

A tu je naša metóda Controller getMetricData ():

@RequestMapping (value = "/ metric-graph-data", method = RequestMethod.GET) @ResponseBody public Object [] [] getMetricData () {return metricService.getGraphData (); }

A tu je ukážka odpovede:

[["Čas", "counter.status.302", "counter.status.200", "counter.status.304"], ["2015-03-26 19:59", 3,12,7], ["26.03.2015 20:00", 0,4,1]]

8. Používanie ovládača Spring Boot 2.x.

V Spring Boot 2 boli API Spring Actuator svedkami veľkej zmeny. Jarné vlastné metriky boli nahradené Mikrometer. Napíšme teda ten istý príklad metrík vyššie s Mikrometer.

8.1. Výmena CounterService S MeterRegistry

Pretože naša aplikácia Spring Boot už závisí od štartéra Actuator, mikrometer je už nakonfigurovaný automaticky. Môžeme vstreknúť MeterRegistry namiesto CounterService. Môžeme použiť rôzne typy Merač na zachytenie metrík. The Počítadlo je jedným z meračov:

@Autowired súkromný register MeterRegistry; private List statusList; @Override public void increaseCount (konečný stav int) {String counterName = "counter.status." + status; registry.counter (counterName) .increment (1); if (! statusList.contains (counterName)) {statusList.add (counterName); }}

8.2. Export počtu pomocou MeterRegistry

V mikrometroch môžeme exportovať Počítadlo hodnoty pomocou MeterRegister:

@Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList statusCount = nový ArrayList (); for (String status: statusList) {Search search = registry.find (status); if (search! = null) {Counter counter = search.counter (); statusCount.add (counter! = null? ((int) counter.count ()): 0); register.remove (counter); } else {statusCount.add (0); }} statusMetricsByMinute.add (statusCount); }

8.3. Publikovanie metrík pomocou Merače

Teraz môžeme tiež zverejniť metriky pomocou Merače spoločnosti MeterRegistry:

@Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList lastMinuteStatuses = initializeStatuses (statusList.size ()); pre (Meter counterMetric: publicMetrics.getMeters ()) {updateMetrics (counterMetric, lastMinuteStatuses); } statusMetricsByMinute.add (lastMinuteStatuses); } private void updateMetrics (final Meter counterMetric, final ArrayList statusCount) {String status = ""; int index = -1; int oldCount = 0; if (counterMetric.getId (). getName (). contains ("counter.status.")) {status = counterMetric.getId (). getName (). substring (15, 18); // príklad 404, 200 appendStatusIfNotExist (status, statusCount); index = statusList.indexOf (stav); oldCount = statusCount.get (index) == null? 0: statusCount.get (index); statusCount.set (index, (int) ((Counter) counterMetric) .count () + oldCount); }}

9. Záver

V tomto článku sme preskúmali niekoľko jednoduchých spôsobov, ako vybudovať niektoré základné možnosti metrík do webovej aplikácie Spring.

Všimnite si, že počítadlá nie sú bezpečné pre vlákna - takže by nemuseli byť presné bez použitia niečoho ako atómové čísla. Toto bolo zámerné len preto, že delta by mala byť malá a stopercentná presnosť nie je cieľom - skôr je to včasné spozorovanie trendov.

Existujú samozrejme vyspelejšie spôsoby zaznamenávania metrík HTTP v aplikácii, ale jedná sa o jednoduchý, ľahký a mimoriadne užitočný spôsob, ako to dosiahnuť bez mimoriadnej zložitosti plnohodnotného nástroja.

Celú implementáciu tohto článku nájdete v projekte GitHub.

REST spodok

Práve som oznámil nové Naučte sa jar kurz zameraný na základy jari 5 a Spring Boot 2:

>> SKONTROLUJTE KURZ

$config[zx-auto] not found$config[zx-overlay] not found