A tavaszi REST API mutatói
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT1. Áttekintés
Ebben az oktatóanyagban integrálunk alapmutatók a Spring REST API-ba.
A metrikus funkcionalitást először egyszerű Servlet szűrőkkel, majd egy rugós indító működtetővel építjük ki.
2. A web.xml
Kezdjük egy szűrő regisztrálásával -MetricFilter" - ba,-be web.xml az alkalmazásunk:
metricFilter org.baeldung.web.metric.MetricFilter metricFilter / *
Vegye figyelembe, hogyan térképezzük fel a szűrőt az összes beérkező kérelem lefedésére - “/*” - ami természetesen teljesen konfigurálható.
3. A Servlet szűrő
Most - hozzuk létre az egyéni szűrőnket:
public class MetricFilter implementálja a Filter {private MetricService metricService; A @Orride public void init (FilterConfig config) ServletException dobja {metricService = (MetricService) WebApplicationContextUtils .getRequiredWebApplicationContext (config.getServletContext ()) .getBean ("metricService"); } @Orride public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) dobja a java.io.IOException, ServletException {HttpServletRequest httpRequest = ((HttpServletRequest) kérelmet); Karakterlánc req = httpRequest.getMethod () + "" + httpRequest.getRequestURI (); chain.doFilter (kérés, válasz); int állapot = ((HttpServletResponse) válasz) .getStatus (); metricService.increaseCount (igény, állapot); }}
Mivel a szűrő nem szabványos bab, nem fogjuk beadni a szűrőt metricService hanem ehelyett manuálisan töltse le - a ServletContext.
Vegye figyelembe azt is, hogy a. Hívásával folytatjuk a szűrőlánc végrehajtását doFilter API itt.
4. Metrikus - Állapotkódszámok
Következő - vessünk egy pillantást egyszerű MetricService:
@Service public class MetricService {private ConcurrentMap statusMetric; public MetricService () {statusMetric = new ConcurrentHashMap (); } public void growthCount (String kérés, int állapot) {Integer statusCount = statusMetric.get (status); if (statusCount == null) {statusMetric.put (status, 1); } else {statusMetric.put (status, statusCount + 1); }} public térkép getStatusMetric () {return statusMetric; }}
Egy memóriát használunk ConcurrentMap hogy tartsa a HTTP állapotkód-típusok számát.
Most - ennek az alapvető mutatónak a megjelenítéséhez - feltérképezzük a Vezérlő módszer:
@RequestMapping (value = "/ status-metric", method = RequestMethod.GET) @ResponseBody public Map getStatusMetric () {return metricService.getStatusMetric (); }
És itt van egy minta válasz:
{ "404":1, "200":6, "409":1 }
5. Metrikus - állapotkódok kérés szerint
Következő - rögzítsük a kérelmek szerinti számlálások mutatóit:
@Service nyilvános osztály MetricService {private ConcurrentMap metricMap; public void growthCount (String kérés, int állapot) {ConcurrentHashMap statusMap = metricMap.get (kérés); if (statusMap == null) {statusMap = új ConcurrentHashMap (); } Egész szám = statusMap.get (status); if (count == null) {count = 1; } else {count ++; } statusMap.put (status, count); metricMap.put (kérés, statusMap); } public térkép getFullMetric () {return metricMap; }}
A mutató eredményeit az API-n keresztül jelenítjük meg:
@RequestMapping (value = "/ metric", method = RequestMethod.GET) @ResponseBody public Map getMetric () {return metricService.getFullMetric (); }
Így néznek ki ezek a mutatók:
{"GET / felhasználók": {"200": 6, "409": 1}, "GET / felhasználók / 1": {"404": 1}}
A fenti példa szerint az API-nak a következő tevékenysége volt:
- „7” kéri a „GET / felhasználók“
- Közülük „6” „200” állapotkód-választ adott, és csak egy a „409” állapotkódot
6. Metrikus - idősoros adatok
Az összesítés némileg hasznos egy alkalmazásban, de ha a rendszer jelentős ideig működik - nehéz megmondani, hogy ezek a mutatók valójában mit jelentenek.
Szüksége van az idő kontextusára, hogy az adatok értelmesek és könnyen értelmezhetők legyenek.
Készítsünk most egy egyszerű időalapú mutatót; nyilvántartást vezetünk az állapotkód percenkénti számáról - az alábbiak szerint:
@Service nyilvános osztály MetricService {private ConcurrentMap timeMap; privát statikus SimpleDateFormat dateFormat = új SimpleDateFormat ("éééé-hh-nn HH: mm"); public void growthCount (String kérés, int állapot) {String time = dateFormat.format (új Date ()); ConcurrentHashMap statusMap = timeMap.get (idő); if (statusMap == null) {statusMap = új ConcurrentHashMap (); } Egész szám = statusMap.get (status); if (count == null) {count = 1; } else {count ++; } statusMap.put (status, count); timeMap.put (idő, statusMap); }}
És a getGraphData ():
public Object [] [] getGraphData () {int colCount = statusMetric.keySet (). size () + 1; Set allStatus = statusMetric.keySet (); int rowCount = timeMap.keySet (). size () + 1; Object [] [] eredmény = new Object [rowCount] [colCount]; eredmény [0] [0] = "Idő"; int j = 1; for (int állapot: allStatus) {eredmény [0] [j] = állapot; j ++; } int i = 1; ConcurrentMap tempMap; a (Belépés bejegyzés: timeMap.entrySet ()) {eredmény [i] [0] = bejegyzés.getKey (); tempMap = entry.getValue (); for (j = 1; j <colCount; j ++) {eredmény [i] [j] = tempMap.get (eredmény [0] [j]); if (eredmény [i] [j] == null) {eredmény [i] [j] = 0; }} i ++; } visszatérési eredmény; }
Ezt most az API-hoz fogjuk feltérképezni:
@RequestMapping (érték = "/ metric-graph-data", módszer = RequestMethod.GET) @ResponseBody nyilvános objektum [] [] getMetricData () {return metricService.getGraphData (); }
És végül - ki fogjuk adni a Google Charts segítségével:
Metrikus grafikon google.load ("vizualizáció", "1", {csomagok: ["corechart"]}); function drawChart () {$ .get ("/ metric-graph-data", function (mydata) {var data = google.visualization.arrayToDataTable (mydata); var options = {title: 'Webhely metrika', hAxis: {title : 'Time', titleTextStyle: {color: '# 333'}}, vAxis: {minValue: 0}}; var chart = new google.visualization.AreaChart (document.getElementById ('chart_div')); chart.draw ( adatok, opciók);}); }
7. A Spring Boot 1.x aktor használata
A következő szakaszokban bekapcsolódunk a Spring Boot Actuator funkcióiba, hogy bemutassuk mutatóinkat.
Először - hozzá kell adnunk a működtető függőségét a sajátunkhoz pom.xml:
org.springframework.boot spring-boot-starter-actuator
7.1. A MetricFilter
Következő - megfordíthatjuk MetricFilter - tényleges tavaszi babba:
@Component public class MetricFilter implement {Filter {@Autowired private MetricService metricService; @Override public void doFilter (ServletRequest kérés, ServletResponse válasz, FilterChain lánc) dobja a java.io.IOException, ServletException {chain.doFilter (kérés, válasz); int állapot = ((HttpServletResponse) válasz) .getStatus (); metricService.increaseCount (állapot); }}
Ez természetesen egy kisebb egyszerűsítés - de ezt érdemes megtenni, hogy megszabaduljon a függőségek korábban manuálisan bekötött vezetékeitől.
7.2. Használata CounterService
Most használjuk a CounterService az egyes állapotkódok előfordulásainak számlálása:
@Service public class MetricService {@Autowired private CounterService counter; private List statusList; public void growthCount (int állapot) {számláló.növekedés ("állapot." + állapot); if (! statusList.contains ("számláló.állapot." + állapot)) {statusList.add ("számláló.állapot." + állapot); }}}
7.3. Mutatók exportálása MetricRepository
Ezután - exportálnunk kell a mutatókat - a MetricRepository:
@Service public class MetricService {@Autowired private MetricRepository repo; privát lista statusMetric; private List statusList; @Scheduled (fixedDelay = 60000) private void exportMetrics () {Metrikus metrika; ArrayList statusCount = new ArrayList (); for (String status: statusList) {metric = repo.findOne (status); if (metrika! = null) {statusCount.add (metric.getValue (). intValue ()); repo.reset (állapot); } else {statusCount.add (0); }} statusMetric.add (statusCount); }}
Ne feledje, hogy számokat tárolunk állapotkódok percenként.
7.4. Tavaszi csizma PublicMetrics
Használhatjuk a Spring Boot-ot is PublicMetrics a metrikák exportálásához saját szűrők használata helyett - az alábbiak szerint:
Először is megvan az ütemezett feladatunk exportmutatók percenként:
@Autowired private MetricReaderPublicMetrics publicMetrics; privát lista statusMetricsByMinute; private List statusList; privát statikus végleges SimpleDateFormat dateFormat = új SimpleDateFormat ("éééé-hh-nn ÓÓ: mm"); @Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList lastMinuteStatuses = initializeStatuses (statusList.size ()); for (Metric counterMetric: publicMetrics.metrics ()) {updateMetrics (counterMetric, lastMinuteStatuses); } statusMetricsByMinute.add (lastMinuteStatuses); }
Természetesen inicializálnunk kell a HTTP állapotkódok listáját:
privát ArrayList initizeStatuses (int méret) {ArrayList counterList = új ArrayList (); for (int i = 0; i <méret; i ++) {counterList.add (0); } return counterList; }
És akkor valóban frissíteni fogjuk a mutatókat állapotkódszám:
private void updateMetrics (Metric counterMetric, ArrayList statusCount) {String status = ""; int index = -1; int oldCount = 0; if (counterMetric.getName (). tartalmazza ("counter.status.")) {status = counterMetric.getName (). szubsztring (15, 18); // 404. példa, 200 appendStatusIfNotExist (status, statusCount); index = statusList.indexOf (állapot); oldCount = statusCount.get (index) == null? 0: statusCount.get (index); statusCount.set (index, counterMetric.getValue (). intValue () + oldCount); }} private void appendStatusIfNotExist (String status, ArrayList statusCount) {if (! statusList.contains (status)) {statusList.add (status); statusCount.add (0); }}
Vegye figyelembe, hogy:
- PublicMetics státuszszámláló neve kezdődikszámláló.állapot" például "számláló.állapot.200.gyökér“
- A jegyzékünkben percenként nyilvántartjuk az állapotszámlálást statusMetricsByMinute
Exportálhatjuk összegyűjtött adatainkat, hogy grafikonba rajzoljuk őket - alábbiak szerint:
public Object [] [] getGraphData () {Date current = new Date (); int colCount = statusList.size () + 1; int rowCount = statusMetricsByMinute.size () + 1; Object [] [] eredmény = new Object [rowCount] [colCount]; eredmény [0] [0] = "Idő"; int j = 1; for (String status: statusList) {eredmény [0] [j] = állapot; j ++; } for (int i = 1; i <rowCount; i ++) {result [i] [0] = dateFormat.format (new Date (current.getTime () - (60000 * (rowCount - i)))); } List minuteOfStatuses; Lista utolsó = új ArrayList (); for (int i = 1; i <rowCount; i ++) {minuteOfStatuses = statusMetricsByMinute.get (i - 1); mert (j = 1; j = j? last.get (j - 1): 0); } while (j <colCount) {eredmény [i] [j] = 0; j ++; } last = minuteOfStatuses; } visszatérési eredmény; }
7.5. Rajzoljon grafikont a metrikák segítségével
Végül - ábrázoljuk ezeket a mutatókat egy 2 dimenziós tömbön keresztül -, hogy aztán ábrázolhassuk őket:
public Object [] [] getGraphData () {Date current = new Date (); int colCount = statusList.size () + 1; int rowCount = statusMetric.size () + 1; Object [] [] eredmény = new Object [rowCount] [colCount]; eredmény [0] [0] = "Idő"; int j = 1; for (String status: statusList) {eredmény [0] [j] = állapot; j ++; } ArrayList temp; for (int i = 1; i <rowCount; i ++) {temp = statusMetric.get (i - 1); eredmény [i] [0] = dateFormat.format (új Date (current.getTime () - (60000 * (rowCount - i)))); for (j = 1; j <= temp.size (); j ++) {eredmény [i] [j] = temp.get (j - 1); } while (j <colCount) {eredmény [i] [j] = 0; j ++; }} visszatérési eredmény; }
És itt van a Controller módszerünk getMetricData ():
@RequestMapping (érték = "/ metric-graph-data", módszer = RequestMethod.GET) @ResponseBody nyilvános objektum [] [] getMetricData () {return metricService.getGraphData (); }
És itt van egy minta válasz:
[["Idő", "számláló.állapot.302", "számláló.állapot.200", "számláló.állapot.304"], ["2015-03-26 19:59", 3,12,7], ["2015-03-26 20:00", 0,4,1]]
8. A Spring Boot 2.x aktor használata
A Spring Boot 2-ben a Spring Actuator API-jai nagy változásnak voltak tanúi. Spring saját mutatóit felváltotta a Mikrométer. Tehát írjuk ugyanazt a metrikát a fenti példával Mikrométer.
8.1. Csere CounterService Val vel MeterRegistry
Mivel a Spring Boot alkalmazásunk már az Actuator indítójától függ, a Micrometer már automatikusan konfigurálva van. Beadhatunk injekciót MeterRegistry ahelyett CounterService. Különböző típusokat használhatunk Méter metrikák rögzítésére. A Számláló a mérők egyike:
@Autowired private MeterRegistry nyilvántartás; private List statusList; @Orride public void growthCount (final int status) {String counterName = "counter.status." + állapot; nyilvántartás.számláló (számlálóNév) .növekedés (1); if (! statusList.contains (counterName)) {statusList.add (counterName); }}
8.2. Számlák exportálása a következővel: MeterRegistry
A mikrométerben exportálhatjuk a Számláló értékek felhasználásával MeterRegistry:
@Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList statusCount = new ArrayList (); for (String status: statusList) {Search search = register.find (status); if (keresés! = null) {Számláló számláló = keresés.számláló (); statusCount.add (számláló! = null? ((int) számláló.szám ()): 0); register.remove (számláló); } else {statusCount.add (0); }} statusMetricsByMinute.add (statusCount); }
8.3. Metrikák közzététele Mérők
Most a Metrics segítségével is közzétehetjük MeterRegistry mérői:
@Scheduled (fixedDelay = 60000) private void exportMetrics () {ArrayList lastMinuteStatuses = initializeStatuses (statusList.size ()); for (Meter counterMetric: publicMetrics.getMeters ()) {updateMetrics (counterMetric, lastMinuteStatuses); } statusMetricsByMinute.add (lastMinuteStatuses); } private void updateMetrics (végső Meter counterMetric, végső ArrayList statusCount) {String status = ""; int index = -1; int oldCount = 0; if (counterMetric.getId (). getName (). tartalmazza ("counter.status.")) {status = counterMetric.getId (). getName (). szubsztring (15, 18); // 404. példa, 200 appendStatusIfNotExist (status, statusCount); index = statusList.indexOf (állapot); oldCount = statusCount.get (index) == null? 0: statusCount.get (index); statusCount.set (index, (int) ((Counter) counterMetric) .count () + oldCount); }}
9. Következtetés
Ebben a cikkben néhány egyszerű módszert tártunk fel, amellyel néhány alapvető mérési képesség beépíthető egy Spring webalkalmazásba.
Vegye figyelembe, hogy a számlálók nem biztonságos szálak - így nem biztos, hogy pontosak, ha nem használnak atomszámokat. Ez csak azért volt szándékos, mert a deltának kicsinek kell lennie, és nem a 100% -os pontosság a cél - inkább a korai trendek észlelése.
Természetesen vannak kiforrottabb módszerek a HTTP-mutatók rögzítésére egy alkalmazásban, de ez egyszerű, könnyű és szuperhasznos módszer a teljes értékű eszköz extra bonyolultsága nélkül.
A cikk teljes megvalósítása megtalálható a GitHub projektben.
REST alsó