Package com.perfino.annotation


package com.perfino.annotation

Annotations for configuring transactions and telemetries in your own code.

What is this API for?

In perfino, you can create transactions from any method invocation. When you configure these transactions in the UI, they are called POJO transactions. They are most suitable for classes that you cannot modify. In your own code, it is easier and more maintainable to use annotations from the perfino API to configure transactions. In perfino, these are called DevOps transactions. The annotations provided by perfino only control the naming of the transactions, the policies have to be configured in the perfino UI. See the corresponding help topics for more information on these concepts.

What is the impact of this API package at runtime?

All annotations have a class retention policy, so using them without perfino has zero impact at runtime: no additional classes are loaded and no code is executed. If your code is monitored by perfino, the annotations are read by the monitoring agent while the classes are loaded.

How do I define a transaction?

Defining a transaction is simple. Add @MethodTransaction to a method, then each method call will be shown as a transaction in perfino. If you have a class where all public methods should be a transaction, annotate that class with @ClassTransaction. If some public methods in that class should be excluded, annotate them with @NoTransaction.

In the above case, the transaction name for the @ClassTransaction is the class name, for the @MethodTransaction it is the method name prepended by the class name. In some cases you will want to customize this name and capture parameters that are passed to a method. This is done by passing a list of @Part annotations as parameters to @ClassTransaction and @MethodTransaction. Each @Part results in a string and all strings are concatenated to form the entire transaction name.

A simple example with one part is

  @MethodTransaction(naming=@Part(text="My transaction"))

If you have more than one part, you have to pass the parts as an array:

  @MethodTransaction(naming = {@Part(text="Plugin "), @Part(Type.INSTANCE_CLASS)})

Another configuration aspect is inheritance. Should overridden methods be considered as well and what class names should be used for naming in that case? The @Inheritance annotation is used as a parameter to configure this behavior. By default, overridden methods are not instrumented.

A complex example looks like this:

   @MethodTransaction(group = "db", naming = {
       @Part(value = Type.CLASS, packageMode = PackageMode.ABBREVIATED),
       @Part(text=" query "),
       @Part(value = Type.PARAMETER, parameterIndex = 1, getterChain = { "getQuery()", "getName()"}),
       @Part(text=" count "),
       @Part(value = Type.PARAMETER, parameterIndex = 2)},
       inheritance = @Inheritance(value = Mode.WITH_SUPERCLASS_NAME, filter = "*Executor")
   )

It puts the transaction in a group, so you can define the policies for multiple annotations with the same group in the perfino UI together. Then, it sets up a composite name consisting of

  • The simple class name of the surrounding class
  • The text " query "
  • The result of calling getQuery().getName() on the second parameter of the annotated method
  • The text " count "
  • The third parameter of the annotated method

The result might look like this: "c.e.a.DbExecutor query SIMPLE_QUERY count 5"

The inheritance filter specifies that methods in all classes that match the wildcard filter "*Executor" should be instrumented. However, the class name for the naming should remain that of the class where the annotation is present.

How do I define a telemetry?

A custom telemetry is defined by annotating a static parameterless method with @Telemetry. The static method must return a numeric value, either a primitive value like int or double or a primitive wrapper instance like java.lang.Integer or java.lang.Double. You can configure multiple lines to be shown in the same telemetry.

In the perfino UI, the telemetry is shown in the VM data views under "Custom telemetries". In addition, you can choose custom telemetries as data sources for sparklines in the dashboard or in the VMs view.

How can I debug the effects of my annotations?

If your annotations do not have the desired effect you can switch on logging to debug the problem. This could be the case if you are missing transactions or your transaction names are not as expected. To enable logging, pass the system property

   perfino.logUser=1

to the monitored VM, e.g. by adding the VM parameter -Dperfino.logUser=1 to the java invocation. The log file is on the machine where the monitored VM is running and is located in the directory

  $HOME/.perfino/log/[VM name].log

To write the log file to a different location, you can set the system property

   perfino.logFile=/path/to/file.log

The log file is only created if there is any logging output. Things you can see in the log file include:

  • Which methods are actually instrumented by your transaction definitions
  • If a filter of an inheritance specification rejects the instrumentation of a candidate method.
  • If an invalid parameter index is requested by a naming @Part of type Part.Type.PARAMETER.