OneAgent and ActiveGate version 1.299 are the last versions supporting OneAgent and ActiveGate Extensions 1.0 framework. You can continue using Extensions 1.0 if you stay at OneAgent or ActiveGate version 1.299. Note that this means you'll be using an unsupported Python version 3.8. We strongly recommend migrating your extensions to the latest Extensions 2.0 framework.
For more information, see General guidance and how to migrate.
While OneAgent automates all extension activity (for example, deciding whether or not a particular extension should be run, restarting error-generating extensions, and gathering required configuration details) there are situations where you might need deeper understanding of internal OneAgent mechanism. For example, if a newly developed extension doesn't start, an outdated version of an extension is running, or you face other unexpected behavior.
Here are the stages of an extension life cycle:
The extension loading process takes place when OneAgent starts. This process evaluates whether or not the extension is compatible with the current version of OneAgent and other extensions.
When the loading process is over, extensions wait until certain conditions are met before they are activated.
OneAgent uses three locations to load extensions:
plugin_deployment
directory - located in the root of your OneAgent installationEach extension is checked for compatibility with already loaded extensions. Two extensions may declare that they require a certain library in a conflicting version. The extension that causes the conflict will not be loaded. The extension causing the conflict id determined by the order of loading, which is the order of locations stated above, and the lexicographical order of the extension names within each location.
For details of possible extension incompatibility and ways to cope with this, see Limitations.
The last 2 locations are used only internally. Files located here should not be modified manually. The plugin_deployment
folder can however be used in any way you want.
In most cases, an extension starts when it detects the process it is to monitor.
Once a extension is loaded, OneAgent decides if it should activate it. Activating an extension triggers an attempt to get the configuration, which is stored on the server. OneAgent also confirms that the extension is enabled. Once available, the extension is run.
The most important factor in extension activation is the process snapshot. This data structure contains information about the important processes recognized on your system. If a match is detected between a process snapshot and information contained in plugin.json
, the extension is activated. In most cases, this information takes the form of detection of a process of a given type. Consequently, if data from the process snapshot disappears, the extension will no longer be active.
The second factor that determines the extension activation is the plugin.json
file. In this file, you can declare which process types are to trigger your extension activation.
3 types of activation are currently available:
So much for the description. Now let's take a look at possible activation types:
In most common cases (as presented in our OneAgent extensions hands-on it's best to create one instance of an extension when a process of a specified type is detected. This requires the following in plugin.json
:
{"entity": "PROCESS_GROUP_INSTANCE","technologies": [ "PYTHON" ],"source": {"activation": "Singleton"},}
With above code snippet included in a plugin.json
, any Python process group instance present in the snapshot will activate the extension. So, for example, the following snapshot would be sufficient:
ProcessSnapshot(host_id=11711730974707348096,entries=[ProcessSnapshotEntry(group_id=9849894537414073908,node_id=0,group_instance_id=11914897446187082808,group_name='plugin_sdk.demo_app',processes=[ProcessInfo(pid=1541,process_name='python3.5',properties={'CmdLine': '-m plugin_sdk.demo_app','WorkDir': '/home/demo','ListeningPorts': '8090'})],properties={"Technologies": "PYTHON"}),ProcessSnapshotEntry(group_id=483552688914919364,node_id=0,group_instance_id=11834758190185815364,group_name='puppet',processes=[ProcessInfo(pid=1257,process_name='puppet',properties={'CmdLine': '/usr/bin/puppet agent', 'WorkDir': '/'})],properties={'Technologies': 'RUBY'})containers=[])
This snapshot contains 2 process groups, one of type python
, which includes plugin_sdk.demo_app
, and one of type ruby
, which runs puppet
.
Only one instance of the extension is created regardless of how many Python processes are running. This means that if the process type is a common one (like Python, Java, or Ruby), you'll need to check if the snapshot contains the process you want to monitor.
In some circumstances, it's best to create one extension instance per process group instance detected on the host. With this approach, you don't need to worry about searching the process snapshot to make sure the process you want to monitor is running. On the downside, if your extension requires configuration, and multiple process group instances of the monitored process are running, you can't use Dynatrace Server to provide the configuration (because it would provide the same configuration to each extension` instance).
A good example of an extension that works fine with the "per process group instance" approach is the MSSQL extension. This extension requires no additional configuration, and its plugin.json
file only declares:
{"entity": "PROCESS_GROUP_INSTANCE","technologies": [ "MSSQL" ]}
So, given this example process snapshot:
ProcessSnapshot(host_id=16649240629743570171, entries=[ProcessSnapshotEntry(group_id=4337044249244370985,node_id=0,group_instance_id=9687064182437432279,group_name='MSSQL10_50.NAMED_ID',processes=[ProcessInfo(pid=26988,process_name='sqlservr.exe',properties={'CmdLine': '-sNAMED_INSTANCE_01', 'WorkDir': 'C:\\Windows\\system32\\'})],properties={'Technologies': 'MSSQL', 'mssql_instance_name': 'NAMED_INSTANCE_01'}),ProcessSnapshotEntry(group_id=12107707763631947228,node_id=0,group_instance_id=10160066155805379574,group_name='MSSQL10.SQLEXPRESS',processes=[ProcessInfo(pid=36632,process_name='sqlservr.exe',properties={'CmdLine': '-sSQLEXPRESS', 'WorkDir': 'C:\\Windows\\system32\\'})],properties={'Technologies': 'MSSQL', 'mssql_instance_name': 'SQLEXPRESS'})containers=[])
Two instances of such an extension would be created by OneAgent, as there are 2 group instances of process technology type Python (in this case, these correspond to MSSQL instances).
In summary, if your extension monitors a process of an uncommon type, and you don't need to use Dynatrace Server for additional configuration, activating a single extention instance per process group instance is a viable approach.
In cases where activation per process type is too open an approach, you can specify additional criteria to determine when an extension should be run. Modify your plugin.json
file to contain a section as below:
{"entity": "PROCESS_GROUP_INSTANCE","technologies": [ "PYTHON" ],"source": {"activation_name_pattern": "^plugin_sdk.demo_app$"}}
In this case the extension will be activated only if detected processes have a name that matches the specified pattern. Matching is done via Python's re.search function. The difference between these two modes of activation is that the first one creates an extension instance for each occurrence of the process that meets the matching criteria. Whereas the second activation mode creates at most 1 instance of the extension.
The last option for activation is to have the extension continuously active. This is achieved with the following configuration:
{"entity": "HOST"}
In this case, as soon as OneAgent receives a process snapshot it activates the extension. This activation type is however not recommended for a few reasons:
plugin.json
file needs also to declare the entity
type that it's associated with. Otherwise the measurements will be associated with the host and it won't be visible on the server.If your extension isn't activated:
demo_oneagent_plugin_snapshot
extension from Extension SDK examples to get the information about all discovered processes, entities IDs and process names which can be used for activation. Just deploy the extension to your production machine with the technology you want to monitor running and you will get the process snapshot information in extension agent log file. The extension activation information will be also displayed on UI in the Properties section of each process as Main technology. There are Python extension activation technologies which can be used as the technologies
property in the plugin.json
and Python extension activation_name_pattern which can be used as the activation_name_pattern
in the source section of plugin.json
.Once active extensions have received their required configurations they're ready to do their work. In the most simple case, an extension query method is run with a 1-minute interval. Nonetheless, there are a few rules you should follow:
OneAgent tries to limit the amount of extension instances. That is, as long as an extension is working properly (no exceptions are thrown from its methods) and its configuration hasn't changed, all calls will happen on the same instance object. This is useful if you want to maintain some state in your extension. This is easily achieved by overriding the initialize()
method.
When the extension configuration changes (for example, if you modified the credentials used to connect to a monitored system) the previous extension instance is discarded, and the query method is called on a new extension instance. Before this occurs you have the option of cleaning up the close()
method, if you overrode it with your extension.
The extension instance will also be replaced if your extension throws exceptions.
ruxit.api.exceptions
, we classify it as a recoverable error. The extension will be quickly restarted a couple times and then OneAgent will attempt to run it every hour.Note that creating a new instance of your extension:
ResultsBuilder
associated with your extension. This remains the same until your extension is deactivated (for example, the monitored process is no longer detected).An extension is closed when its life comes to an end. At the end of the road, the close()
method is called, so if your extension acquired some resources, it can release them. The most common reasons for calling this method are: