stevensouza / jamonapi

Another repo for jamonapi.com which is primarily hosted on sourceforge
57 stars 24 forks source link

Accessing listener data #14

Closed jchappelle closed 8 years ago

jchappelle commented 8 years ago

I'm having trouble accessing data for a registered listener. I'm integrating JAMon into a web application that is implemented with Apache Wicket. I've built screens similar to the management app that lets you view the monitoring data.

Now I'm trying to implement a feature where we can add listeners through the admin page and I'm needing to know how to register a listener and read the captured data.

Here's what I have so far: Monitor monitor = MonitorFactory.start(label); JAMonBufferListener listener = (JAMonBufferListener)JAMonListenerFactory.get("NLargestValueBuffer"); monitor.addListener("value", listener); try { Thread.sleep(sleepTime); } finally { monitor.stop(); }

Later in my code I am trying to print out the data like so: System.out.println(monitor.getListenerType("value").getHeader()); System.out.println(monitor.getListenerType("value").getData()); The header array just contains [Label] and the getData only has the name of the NLargestValueBuffer.

What am I doing wrong? I want to get the data stored by the listener, in this case the largest value or values.

Also it would be great to add this information to the documentation for people like me trying to integrate into their app.

Thanks for any help and really cool library by the way.

stevensouza commented 8 years ago

I'll look at this later when I have a little more time. In the meantime I would look at the tests and the jsp that adds listeners.

Is this line helpful: mon.getListenerType(listenerType).getListener();

stevensouza commented 8 years ago

This looks like it might be helpful from mondetail.jsp.

JAMonListener listener=mon.getListenerType(listenerType).getListener(currentListenerName);

DetailData detailData = ((JAMonBufferListener)listener).getDetailData();

String[] header = detailData.getHeader();

Object[][] data = detailData.getData();

The typecast is a bit ugly...

stevensouza commented 8 years ago

By the way I think mondetail.jsp displays the data and monmanage.jsp allows you to add listeners.

jchappelle commented 8 years ago

Thanks @stevensouza. That last code snippet worked like a charm!

stevensouza commented 8 years ago

Glad it worked. Would love to see screen snapshots of the web app you are building that shows the data.

Also, you might be interested in Automon which allows you to monitor any java method or class (including 3rd party and jdk classes). It uses jamon (or other tools) for the monitoring. It is all done declaratively. Here it is. If you have any questions about it let me know.

https://github.com/stevensouza/automon

Here is an example of the type of info it can track...

image

jchappelle commented 8 years ago

I did look at that and it looks good. For our situation I don't want to have another war file to deploy. We develop on-premise software for banks. We have some software that is hosted but we have lots that are on-premise and I always try to shy away from something that adds steps to our operations' checklists. It probably wouldn't be too much but it was actually really easy to integrate your code with Wicket.

There's a wicketstuff project that was already integrating jamon and wicket. You can see it here: https://github.com/wicketstuff/core. You might have to search the page for jamon to find it because they have quite a few little projects for wicket integration on there.

It didn't do everything that I needed so I basically wrote my own version. I currently don't have any listener support but I'm not sure we are going to need it. I can always add it in the future.

Here's a quick screenshot. Our software does fraud analysis of transactions and also handles notifying customers about suspicious activity and allows them to accept or reject it. So what what you are seeing are details about some of the fraud system rules and also about the customer notification statistics. It's all dummy data on my machine so it's not really representative of what I expect to see in the wild. Can't wait to get it out the door and see how it helps us tune performance.

The link is the monitor label and the details put together, the details are in the parenthesis. I wasn't sure if the details make the keys unique or not, my hopes was that it doesn't, because I want to be able to identify our entity objects by title but I also want to maintain the statistics if someone renames it. So the numbers you see in the titles are the primary keys of the table.

I don't show it here but if you click the link you can see range data for that monitor below the table.

Any suggestions or pointers are appreciated.

performance

jchappelle commented 8 years ago

One more thing, the "Fraud Analysis" monitor above was actually created from a spring-batch integration. It's really nothing special but I'll share it here just in case it sparks an idea. We have a job called "Fraud Analysis" and I wanted to create a Monitor that could track the performance of the overall job since all the other items above are internals of the job.

Spring Batch has a JobExecutionListener interface that tells you about when a job starts and ends. Here's my code if you're interested.

/**
 * Uses JAMon library to time the job and record statistics in the {@code MonitorFactory}. It's safe to declare this as
 * a singleton because it keeps a map of monitors keyed by the JobExecution id. However, if you declare it as a singleton
 * then it's recommended to use the default constructor so that the job name will be used as the monitor label. Other
 * constructors let you specify the label and that label will be fixed for the life of this listener.
 */
public class JamonJobExecutionListener extends JobExecutionListenerSupport
{
    private final MonKey monitorKey;

    private Map<Long, Monitor> monitors = new ConcurrentHashMap<>();

    /**
     * Uses the job name as the monitor key. It's safe to use this constructor if you are
     * declaring this bean as a singleton.
     */
    public JamonJobExecutionListener()
    {
        this.monitorKey = null;
    }

    /**
     * Uses the specified label as the monitor summary label. It's recommended to declare this
     * bean with JobScope if using this constructor.
     * @param label The summary label to use when starting the monitor
     */
    public JamonJobExecutionListener(String label)
    {
        this(new MonKeyImp(label, "ms."));
    }

    /**
     * Uses the specified {@code MonKey} to start the monitor. It's recommended to declare this
     * bean with JobScope if using this constructor.
     * @param monitorKey The {@code MonKey} to use when starting the monitor
     */
    public JamonJobExecutionListener(MonKey monitorKey)
    {
        this.monitorKey = monitorKey;
    }

    @Override
    public void beforeJob(JobExecution jobExecution)
    {
        Monitor monitor = startMonitor(jobExecution);

        monitors.put(jobExecution.getId(), monitor);
    }

    @Override
    public void afterJob(JobExecution jobExecution)
    {
        Monitor monitor = monitors.get(jobExecution.getId());
        if(monitor != null)
        {
            monitor.stop();
            monitors.remove(jobExecution.getId());
        }
    }

    private Monitor startMonitor(JobExecution jobExecution)
    {
        Monitor monitor = null;
        if(monitorKey == null)
        {
            monitor = MonitorFactory.start(jobExecution.getJobInstance().getJobName());
        }
        else
        {
            monitor = MonitorFactory.start(monitorKey);
        }
        return monitor;
    }
}
stevensouza commented 8 years ago

For our situation I don't want to have another war file to deploy. Automon doesn't require a war file. It is a small jar file. Here are some sample programs and an explanation: https://github.com/stevensouza/automon/tree/master/examples . It is really easy. Basically add the agent and automon.jar to the way you would normally start up your program. Also you need the config.xml file that declares what classes/methods to monitor. Here is an example:

  • java -Dorg.aspectj.weaver.loadtime.configuration=file:config/myaopconfig.xml -javaagent:libs/aspectjweaver.jar -classpath automon-1.0.1-SNAPSHOT.jar:myapp.jar:jamon-2.81.jar com.stevesouza.myapp.MyProgram

Here is an example program using jamon. https://github.com/stevensouza/automon/blob/master/examples/hello-world-unwoven-jamon-ltw.sh

If you use springbeans it is even easier. If you need help on this if it makes sense in your case let me know.

The link is the monitor label and the details put together, the details are in the parenthesis. I wasn't sure if the details make the keys unique or not, my hopes was that it doesn't, because I want to be able to identify our entity objects by title but I also want to maintain the statistics if someone renames it

Jamon doesn't use the 'details' as part of the primary key, so you can feel free to pass in whatever you want. The details are useful for when you have listeners. It allows you to view this full context info. For example when an exception is thrown the full stacktrace is in the details. This allows developers to view the most recent N stacktraces. Very handy.

Are you saying that somehow your screen uses details as part of a primary key? Be careful with that as you don't want your data to grow to big. As an fyi Jamon lets you limit the number of monitors so you don't accidentally grow your data too big.

MonitorFactory. setMaxNumMonitors(1000);

https://github.com/stevensouza/jamonapi/blob/master/jamon/src/main/java/com/jamonapi/MonitorFactory.java#L398

Steve

jchappelle commented 8 years ago

Are you saying that somehow your screen uses details as part of a primary key?

No. I'm saying we have a criterion entity with say primary key 123. The title of it is "Walmart over $100". When I create the Monkey I do the following:

MonKeyImp key = new MonKeyImp("Fraud Analysis.Criterion." + criterionConfig.getEntityId(), criterionConfig.getTitle(), "ms.");

Notice I put the title in the details here but I also put the entity id(primary key) as part of the summary label.

The reason I'm doing this is because someone might decide to rename that record to "Grocery stores over $100". On our screen, without the details, we would see "Fraud Analysis.Criterion.123" as the label column which means we would then have to open the database and lookup that entity id to see which criterion that is in reference to. By adding the details in and making it say "Fraud Analysis.Criterion.123(Walmart over $100)" I'm able to provide some context at a glance without the admin user having to lookup anything in the database.

Jamon doesn't use the 'details' as part of the primary key

Now from what you are saying if someone renames it to "Grocery stores over $100", we should start seeing "Fraud Analysis.Criterion.123(Grocery stores over $100)" with the same statistics as before since the details is not part of the key which is exactly what I was hoping for.

Automon looks good and easy to use. We use spring heavily. We have written AOP code for a few things like method level trace logging so I understand how to plug that in and I think monitoring is a perfect cross cutting concern use case to use AOP. The reason I didn't explore the AOP route further during this go-round is because some of the finer grained details weren't encapsulated within their own interface. I intend to refactor them and get there but I wanted to dip my toe in the JAMon waters first. So far the water is nice!

I would love to be able to trend statistics to be able to see how performance is affected after patches or other events. I've read about jarep but I can't find any documentation on how to get that running or how to embed it. Can you give me any suggestions in the area of reporting? I've thought about simply having a scheduled job that dumps the monitor data to a table with a creation timestamp included. The thing I don't want is for that job to run right after a patch and dump all zeros to the table and skew the trends. I suppose I could check the hits count and only write after it's had a statistically significant number of hits.

Sorry to keep asking questions. You've been a great help so far so I'm taking advantage. :-)

stevensouza commented 8 years ago

Now from what you are saying if someone renames it to "Grocery stores over $100", we should start seeing "Fraud Analysis.Criterion.123(Grocery stores over $100)" with the same statistics as before since the details is not part of the key which is exactly what I was hoping for.

sounds right, but I would test it.

If you use spring and only want to monitor Spring methods then it wouldn't make sense to use automon. Automon comes in handy in that you can monitor ANY class (even jdk classes and 3rd party classes) whereas spring aop only allows spring beans to be monitored. Spring AOP has a jamon aspect included.

I would love to be able to trend statistics to be able to see how performance is affected after patches or other events.

I don't know jarep. In the past I have collected statistics and on a timer saved them. As you mentioned you can check the data first to see if you want to save it.

Steve

jchappelle commented 8 years ago

Good deal. Thanks for all your help!