2015-02-13 13 views
31

Sto tentando di aggiungere metriche a un'applicazione Java semplice utilizzando le metriche di codahale. Mi piacerebbe usare l'annotazione @Timed, ma non è chiaro per me quale MetricRegistry utilizza, o come dirgli quale MetricRegistry usare. L'applicazione è una semplice applicazione Java 8, realizzata con Maven 3, senza Spring, senza Hibernate.Metriche di Codahale: utilizzo dell'annotazione delle metriche @Timed in Java semplice

non riesco a trovare alcuna documentazione su come implementare @Timed nella documentazione dropwizard: https://dropwizard.github.io/metrics/3.1.0/manual/

Ho aggiunto queste dipendenze:

<dependency> 
    <groupId>io.dropwizard.metrics</groupId> 
    <artifactId>metrics-core</artifactId> 
    <version>3.1.0</version> 
</dependency> 
<dependency> 
    <groupId>com.codahale.metrics</groupId> 
    <artifactId>metrics-annotation</artifactId> 
    <version>3.0.2</version> 
</dependency> 

Quando uso una chiamata programmatico a Timer, I possono ottenere rapporti perché so che MetricsRegistry viene utilizzato:

static final MetricRegistry metrics = new MetricRegistry(); 
private void update() throws SQLException { 
    Timer.Context time = metrics.timer("domainobject.update").time(); 
    try { 
    [...] 
    } finally { 
    time.stop(); 
    } 
} 

Ma quando uso il molto più elegante di annotazione @Timed, non ho idea whic h Registro di sistema viene utilizzato, e quindi non in grado di creare un reporter, il che significa che non posso ottenere le metriche riportati (io non sono nemmeno sicuro se questo in realtà fa nulla):

@Timed(name = "domainobject.update") 
private void update() throws SQLException { 
    [...] 
} 

Si prega di avvisare su come fare le annotazioni @Timed e altre metriche funzionano in una normale applicazione Java.

Altre informazioni: Il motivo per cui trovo questo strano è che ho aggiunto il framework Lombok e le annotazioni @ Slf4j funzionano. Ho aggiunto Lombok come una dipendenza nella pom.xml Maven:

<dependency> 
    <groupId>org.projectlombok</groupId> 
    <artifactId>lombok</artifactId> 
    <version>1.14.8</version> 
</dependency> 

E posso usare l'annotazione @ classe Sl4fj per aggiungere un logger alla classe senza ingombrare le variabili membro:

@Slf4j 
public class App { 
    public void logsome(){ 
    log.info("Hello there"); 
    } 
} 

Quindi, se ciò è possibile semplicemente aggiungendo una dipendenza, ritengo che manchi solo una dipendenza o una configurazione per far funzionare l'annotazione codahale @Timed, come descritto sopra.

(a proposito, check out Lombok, renderà la vita più facile: http://projectlombok.org/)

+0

Penso che sarà out-of-fortuna senza molla AOP o impostare manualmente fino AspectJ per tessere le classi. Questo tipo di cose funziona solo con AOP, quindi hai bisogno di qualcosa per fornirlo nelle tue classi. Ad esempio, Spring AOP utilizza JDK Proxies, CGLIB o AspectJ per ottenere questo – Alex

+0

Quindi AspectJ sarebbe la strada da percorrere? Come faccio a farlo? – Rolf

+0

Ancora più interessante: perché @ Slf4j funziona, per esempio, e @ Timed no? Non sto usando esplicitamente AspectJ per far funzionare Slf4j. – Rolf

risposta

12

Per farla breve, non è possibile utilizzare @Timed senza un qualche tipo di AOP (sia esso Spring AOP o AspectJ).

Una settimana o due fa, ho anche deciso di aggiungere metriche al nostro progetto e ho scelto AspectJ per questo compito (principalmente perché l'ho usato in passato per scopi simili e perché consente la tessitura in tempo compilabile mentre Spring consente solo runtime via proxy).

Dovresti essere in grado di trovare tutte le informazioni e le istruzioni necessarie qui: https://github.com/astefanutti/metrics-aspectj.

Quanto a Lombok, immagino usano processore integrato annotazioni javac:

Un altro punto di contesa è l'implementazione sia del codice sostenere l'integrazione IDE così come il processore javac annotazione. Entrambi questi pezzi di Project Lombok utilizzano API non pubbliche per realizzare la loro stregoneria. Ciò significa che c'è il rischio che Project Lombok venga danneggiato con le successive release IDE o JDK.

+0

Questo sembra il modo per ottenere @ Timed funziona davvero, grazie, ma ora Lombok e AspectJ entrano in una discussione nel mio ciclo di produzione. AspectJ si lamenta dell'annotazione @ Slf4j. Devo capire come farli giocare bene. – Rolf

+0

Sembra che Lombok e AspectJ non stiano sempre giocando bene: https://stackoverflow.com/questions/25903686/lombok-does-not-work-with-aspectj – Rolf

+0

Tempo per decisioni difficili. Ho provato a rimuovere Lombok a favore dell'annotazione @Timed, ma le cose di AspectJ mi stanno dando un momento così difficile, ed è così difficile e incomprensibile da eseguire il debug, mi sono arreso. Rende il progetto molto più complesso e crea un problema più grande di quello che sta risolvendo. Ho contrassegnato la tua risposta come "risposta" perché * è * la risposta, è troppo grande di una seccatura per il mio piccolo progetto (e il mio piccolo cervello). Codifica a mano le chiamate a Codahale Timer ora. Grazie! – Rolf

5

utilizzare il built-in MetricRegistry si accede dal parametro bootstrap nel metodo di inizializzazione della classe di applicazione.

@Override 
public void initialize(final Bootstrap<Configuration> bootstrap) { 
    final JmxReporter reporter = JmxReporter.forRegistry(bootstrap.getMetricRegistry()).build(); 
    reporter.start(); 
} 
3

AOP è eccessivo e non appropriato per l'uso di @timed, in generale parlando.

Il registro delle metriche predefinito scrive metriche @timed su ConcurrentHashMap e non associa alcun listener significativo.

DropWizard Bootstrap costruttore:

/** 
* Creates a new {@link Bootstrap} for the given application. 
* @param application a Dropwizard {@link Application} 
*/ 
public Bootstrap(Application<T> application) { 
    this.application = application; 
    this.objectMapper = Jackson.newObjectMapper(); 
    this.bundles = Lists.newArrayList(); 
    this.configuredBundles = Lists.newArrayList(); 
    this.commands = Lists.newArrayList(); 
    this.validatorFactory = Validators.newValidatorFactory(); 


    // returns new ConcurrentHashMap<String, Metric>(); 
    this.metricRegistry = new MetricRegistry(); 


    this.configurationSourceProvider = new FileConfigurationSourceProvider(); 
    this.classLoader = Thread.currentThread().getContextClassLoader(); 
    this.configurationFactoryFactory = new DefaultConfigurationFactoryFactory<T>(); 
} 

Quindi è necessario per costruire/start/registrare il Registro di metrica appropriata in per vedere i risultati.

Qui io uso JMX:

@Override 
public void initialize(Bootstrap<PayloadStorageConfiguration> bootstrap) { 
    JmxReporter.forRegistry(bootstrap.getMetricRegistry()).build().start(); 
} 

Questo è tutto quello che devi fare.

Ecco un esempio di output (eseguire jconsole contro la vostra applicazione Java/server per visualizzare i risultati JMX):

enter image description here

0

Si potrebbe anche usare stagemonitor-core per questo. Vedere la documentazione here e here. Il vantaggio è che stagemonitor (che è gratuito & open source btw) non dipende da alcun AOP basato su container come Spring AOP o EJB interceptor. Utilizza la manipolazione bytecode tramite l'allegato runtime, il che significa che non è nemmeno necessario aggiungere un flag -javaagent all'avvio dell'applicazione: è sufficiente una semplice dipendenza.

Se si desidera misurare il tempo di esecuzione in un'applicazione Web o in un'applicazione EJB remota, non è nemmeno necessario annotare manualmente il codice. Inoltre, stagemonitor offre dashboard Grafana e Kibana preconfigurati.

Disclaimer: io sono uno degli sviluppatori di stagemonitor

8

Utilizzando @Timed in realtà non richiedono l'uso di AOP, come precedentemente affermato nella risposta top-rated, se sei all'interno di un contenitore e usando una delle librerie di strumentazione di Dropwizard. Vedi il modulo Jersey 2.x per esempio, che puoi vedere usa reflection (come gli altri che ho visto), se leggi il source.

È possibile leggere tutti questi moduli in the Dropwizard docs con i corrispondenti punti "Strumentazione ____".

Comprendo che l'OP non funzionava esplicitamente all'interno di un contenitore di questo tipo, ma volevo offrire queste informazioni, poiché molti di noi che cercano questa risposta potrebbero lavorare su un moderno servizio Web in grado di registrare tali risorse nel proprio ambiente runtime .

0

Nelle versioni più recenti di Dropwizard (sto utilizzando la versione 0.9.2), è possibile accedere all'impostazione predefinita MetricRegistry tramite l'ambiente di installazione io.dropwizard.setup.Environment. Questo valore predefinito MetricRegistry è già associato a InstrumentedResourceMethodApplicationListener, che ascolta tutte le metriche delle risorse.

Se sei registrato una risorsa con la JerseyEnvironment come sotto,

environment.jersey().register(resource); 

è sufficiente annotare il metodo di risorsa (o classe) con @Timed, @Metered o @ExceptionMetered per registrare i rispettivi parametri.

@POST 
@Timed 
public String show() { 
    return "yay"; 
} 

È possibile assegnare un Reporter (come un Slf4jReporter o JmxReporter) al default MetricRegistry come sotto

Slf4jReporter.forRegistry(environment.metrics()).build(); 

Come test rapido per verificare se sono state effettivamente registrato le metriche, si può fare un GET chiama all'URL http://localhost:8081/metrics o l'URL della metrica amministrativa corrispondente nell'ambiente di test.

Alcune altre versioni richiedono la registrazione in modo esplicito un InstrumentedResourceMethodApplicationListener come mostrato in this Doc

Problemi correlati