> For the complete documentation index, see [llms.txt](https://docs.flopsar.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flopsar.com/7/developer-guide/agent-plugins.md).

# Agent Plugins

The Flopsar Agent can operate as a standalone solution or be extended with user-defined custom code. It is a robust engine that supports extensibility through plugins. These extensions consist of additional JAR files containing user-defined POJO (Plain Old Java Object) classes. The JAR files can be uploaded directly to the Flopsar server, enabling the agent's capabilities to be extended.

This extensibility mechanism allows users to enhance application diagnostics and trace data flow more effectively, making Flopsar an open and adaptable tool. With the plugin system, users can process data within instrumented methods, providing deeper insights and custom processing capabilities.

There are two types of extensions, which can be used: **standard** and **custom**.

## Standard

The **standard** extension is embedded in the agent. This extension will execute the following method on each argument it gets:

```java
public static java.lang.String valueOf(java.lang.Object);
```

and return a result in a form of concatenated pairs of parameter identifiers and the corresponding `valueOf` function result. The following parameters are returned (in order of appearance):

* `THIS` : If the instrumented method is static, this parameter is `null`, otherwise a class instance the method is executed on.
* `ARGS` : List of all arguments of the instrumented method.
* `RET`: Only if the instrumented method does not return void and the instrumentation is performed at the method exit.

## Custom

If the standard extension is not enough and you want to extract extra information (or preprocess values), implement a custom extension. Configure the profile, create a simple POJO, and implement a single method:

```java
public static java.lang.String myFormatter(java.lang.Object[] args)
```

{% hint style="warning" %}
You can give any name to the above method but the signature of the method must be preserved. Otherwise, it will not work.
{% endhint %}

The `args` argument of the extension method is an array of the instrumented method arguments delivered to your method. These are your original application objects, not clones. When configuration is correct, the agent injects your code into the instrumented methods. Injection can happen at method entry or method exit. Your formatter runs inside the instrumented method, so keep overhead low. The `args` array contains (in order):

* **`args[0]`** If the instrumented method is static this element is `null`, otherwise it is a reference to a class instance the instrumented method is executed on.
* **`args[1..N]`** List of all arguments of the instrumented method in the same order as they appear in the method signature. These are the references to your original application objects, not some *clones*.
* **`args[N+1]`** It is a reference to the object instance this method returns. **Please note, this argument is passed to the formatter if and only if the instrumentation is performed at the end of the method**.

where **N** is the number of the instrumented method arguments.

You decide what extra features the agent will have: extract fields from arguments, format values the built-in handlers cannot, or enrich the recorded invocation — still without changing application source.

{% hint style="info" %}
Use `U+001E` as a separator in your code. Otherwise, the result will not be formatted properly in the Workstation.
{% endhint %}

Your result should always consist of pairs of keys and values. `U+001E` separates each entry in the result, which means you should always have an odd number of separators. The resulting string size cannot be greater than 8192 B, otherwise it will be truncated.

Tips when writing extensions:

* Design and implement extensions with performance in mind. If your code performs poorly, obviously the instrumented methods will perform poorly as well.
* Use `try-catch` block to protect your application from any errors you can make in your extension implementation. Otherwise, any errors inside the extension code can interfere with your application processing.
* Do not modify arguments delivered to your extension since they are your genuine application objects. Make sure that whatever you do with them will not cause any problem to your application flow.
* Do not use reflection unless there is no other way.
* Avoid allocating many short-lived objects; that increases GC overhead.
* Deploy extension classes in separate JAR files to reduce class-loading issues.
* Keep extension code stateless.

## Example

Suppose, you have some method:

```java
public FooBar foo(foo.bar.Object1, foo.bar.Object2, ...);
```

and you are interested in some additional information extracted from the first and second arguments. Your extension implementation can look like the one below:

```java
public static java.lang.String myFormatter(java.lang.Object[] args){

        final char SEPARATOR = 0x1E;

        try {
                foo.bar.Object0 _this = (foo.bar.Object0)args[0];
                foo.bar.Object1 obj1 = (foo.bar.Object1)args[1];
                foo.bar.Object2 obj2 = (foo.bar.Object2)args[2];
                /*
                 implement your logic here
                 to produce string output.
                */
                String output1 = some_logic1(obj1);
                String output2 = some_logic2(obj2);

                return "Object1"+SEPARATOR+output1+SEPARATOR+"Object2"+SEPARATOR+output2;

        } catch(Throwable ex){
                return "Error"+SEPARATOR+ex.getMessage();
        }
}
```

{% hint style="warning" %}
Flopsar Technology cannot be held accountable for any damage done by badly written user's extensions.
{% endhint %}
