Dynatrace Extensions SDK for Python¶
dt-extensions-sdk
is a Python library and a toolbox for building Python
extensions for Extensions Framework 2.0. It provides a ready to use template
and a set of tools to build, test, package, and ship your extension.
What dt-sdk can do
Generate a new extension from template
Run extensions locally
Build and sign extensions
Installation¶
dt-extensions-sdk
can be installed from PyPI.
For other installation options and Requirements
please see Installation.
pip install dt-extensions-sdk[cli]
Installing in virtual environment¶
This approach is recommended if you are working on several extensions:
python -m venv .venv
source .venv/bin/activate
pip install dt-extensions-sdk
Keeping each extension in its own virtual environment is a good practice. It guarantees that each extension has its own set of dependencies and does not interfere with other extensions.
Quick Start¶
Once dt-sdk
is installed, we are ready to create our first extension.
Create extension¶
Let’s generate a new extension called my_extension from scratch using the Create command:
$ dt-sdk create my_extension
Extension created at my_extension
This will create a new directory called my_extension with the following structure:
my_extension
├── README.md
├── activation.json
├── extension
│ ├── activationSchema.json
│ └── extension.yaml
├── my_extension
│ ├── __init__.py
│ └── __main__.py
└── setup.py
What do these files mean?
Be sure to checkout the Extension Structure guide for the detailed explanation of why each file is needed and what needs to be in there.
Run extension¶
In order to launch the extension locally, we can use the Run command:
$ cd my_extension
$ dt-sdk run
Running: .venv/dt-extensions-sdk/bin/python -m my_extension --activationconfig activation.json
[INFO] api (MainThread): -----------------------------------------------------
[INFO] api (MainThread): Starting <class '__main__.ExtensionImpl'> my_extension, version: 1.1.0
[INFO] api (ThreadPoolExecutor-1_0): send_status: '{"status": "OK", "message": "", "timestamp": 1699993566909}'
[INFO] api (ThreadPoolExecutor-1_1): send_sfm_metric: dsfm:datasource.python.threads,dt.extension.config.id="development_config_id" count,delta=4
[INFO] dynatrace_extension.sdk.extension (ThreadPoolExecutor-0_0): query method started for my_extension.
[INFO] dynatrace_extension.sdk.extension (ThreadPoolExecutor-0_0): query method ended for my_extension.
Query method and scheduling
The query()
method in __main__.py
file is scheduled to run every 60 seconds.
You can also schedule other methods to run at different intervals by overriding
dynatrace_extension.Extension.initialize()
method:
schedule:
def initialize(self):
# Schedule the my_method method to run every 5 minutes
self.schedule(self.my_method, timedelta(minutes=5))
We can see that the extension is running and the query method was successfully executed. For now, it does not do anything useful, so it finishes immediately.
If we now press Ctrl+C
to stop the execution, we will see the following output:
^C[INFO] api (MainThread): SIGINT captured. Flushing metrics and exiting...
[INFO] api (MainThread): send_metric: my_metric,my_dimension="dimension1" gauge,1 1699993566910
[INFO] api (MainThread): Sent 1 metric lines to EEC: [MintResponse(lines_ok=1, lines_invalid=0, error=None, warnings=None)]
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.threads,dt.extension.config.id="development_config_id" count,delta=4
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.time,callback="query",dt.extension.config.id="development_config_id" gauge,0.0003
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.total.count,callback="query",dt.extension.config.id="development_config_id" count,delta=1
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.count,callback="query",dt.extension.config.id="development_config_id" count,delta=1
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.ok.count,callback="query",dt.extension.config.id="development_config_id" count,delta=1
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.timeout.count,callback="query",dt.extension.config.id="development_config_id" count,delta=0
[INFO] api (MainThread): send_sfm_metric: dsfm:datasource.python.execution.exception.count,callback="query",dt.extension.config.id="development_config_id" count,delta=0
We can see here, that the extension has sent 1 metric to the Dynatrace. That’s because
the query()
contains the following line:
# Report metrics with
self.report_metric("my_metric", 1, dimensions={"my_dimension": "dimension1"})
This code sends a single data point for the metric called my_metric
with
value 1
and dimension my_dimension
with value dimension1
.
The next data point for same metric will be sent in 60 seconds, when the query()
method executes again.
Self monitoring metrics
You might have noticed that there are some additional metrics being sent to Dynatrace. These are called self monitoring metrics and they allow the environment to understand how the extension is performing and whether everything is fine with the assigned monitoring configuration.
Generate certificates¶
In order to sign the extension, we need to have a certificate that is uploaded to the environment and to the OneAgent or Activegate hosts that will run the extension.
Already have the certificate?
If you already have the certificate and it is uploaded to the environment and hosts you can skip this step and go directly to the build step.
In order to generate a new certificate, we can use the Generate Certificates command:
$ dt-sdk gencerts
Running: dt ext genca --ca-cert /Users/myuser/.dynatrace/certificates/ca.pem --ca-key
/Users/myuser/.dynatrace/certificates/ca.key --no-ca-passphrase
Generating CA...
Wrote CA private key: /Users/myuser/.dynatrace/certificates/ca.key
Wrote CA certificate: /Users/myuser/.dynatrace/certificates/ca.pem
Running: dt ext generate-developer-pem --output /Users/myuser/.dynatrace/certificates/developer.pem --name Acme
--ca-crt /Users/myuser/.dynatrace/certificates/ca.pem --ca-key /Users/myuser/.dynatrace/certificates/ca.key
Loading CA private key /Users/myuser/.dynatrace/certificates/ca.key
Loading CA certificate /Users/myuser/.dynatrace/certificates/ca.pem
Generating developer certificate...
Wrote developer certificate: /Users/myuser/.dynatrace/certificates/developer.pem
Wrote developer private key: /Users/myuser/.dynatrace/certificates/developer.pem
This will place the developer certificates in the default directory.
Detailed documentation
For more information on how to generate and upload certificates, please see certificates documentation.
Build extension¶
Now that we have a working extension and a certificate to sing it with, we can build it using the Build command, which will perform the following steps:
Download the dependencies
Build a wheel
Package the build into a
.zip
archiveSign the archive with the given certificate
$ dt-sdk build
Building and signing extension from my_extension to None
Stage 1 - Download and build dependencies
Cleaning my_extension/extension/lib
Downloading dependencies to my_extension/extension/lib
Running: .venv/dt-extensions-sdk/bin/python -m pip wheel -w extension/lib .
Processing my_extension
Preparing metadata (setup.py) ... done
Collecting dt-extensions-sdk (from my-extension==0.0.1)
Using cached dt_extensions_sdk-1.1.0-py3-none-any.whl.metadata (1.8 kB)
Using cached dt_extensions_sdk-1.1.0-py3-none-any.whl (42 kB)
Saved ./extension/lib/dt_extensions_sdk-1.1.0-py3-none-any.whl
Building wheels for collected packages: my-extension
Building wheel for my-extension (setup.py) ... done
Created wheel for my-extension: filename=my_extension-0.0.1-py3-none-any.whl size=1985 sha256=19039181b70d68105512ad52b80129368724b3f15e0ba2a2b5fdb98cc710e705
Stored in directory: /private/var/folders/jd/s1xmb3jj31gcd11g3p4ncctm5q47pj/T/pip-ephem-wheel-cache-zqkysr41/wheels/9c/1c/44/e47f092abb0d0b281251f7cfc7b8d5993c2c5678b3acd80751
Successfully built my-extension
Installed dependencies to my_extension/extension/lib
Stage 2 - Create the extension zip file
Running: dt ext assemble --source my_extension/extension --output my_extension/dist/extension.zip --force
my_extension/dist/extension.zip file already exists, it will be overwritten!
Building my_extension/dist/extension.zip from my_extension/extension
Adding file: my_extension/extension/lib/my_extension-0.0.1-py3-none-any.whl as lib/my_extension-0.0.1-py3-none-any.whl
Adding file: my_extension/extension/lib/dt_extensions_sdk-1.1.0-py3-none-any.whl as lib/dt_extensions_sdk-1.1.0-py3-none-any.whl
Adding file: my_extension/extension/extension.yaml as extension.yaml
Adding file: my_extension/extension/activationSchema.json as activationSchema.json
Built the extension zip file to my_extension/dist/extension.zip
Stage 3 - Sign the extension
Signing file my_extension/dist/extension.zip to my_extension/dist/custom_my-extension-0.0.1.zip with certificate
/Users/myuser/.dynatrace/certificates/developer.pem
Running: dt ext sign --src my_extension/dist/extension.zip --output my_extension/dist/custom_my-extension-0.0.1.zip
--key /Users/myuser/.dynatrace/certificates/developer.pem --force
Created signed extension file my_extension/dist/custom_my-extension-0.0.1.zip
Stage 4 - Delete my_extension/dist/extension.zip
Once completed, the signed build will be placed in the dist
directory:
dist/custom_my-extension-0.0.1.zip
Upload extension¶
Finally, we can upload the extension to the environment using the Upload command. It requires us to provide the environment URL and an API token with the permission to upload extensions. This can be done via environment variables or command line arguments
$ dt-sdk upload
Uploading extension dist/custom_my-extension-0.0.1.zip to https://<your_environment_url_here>/
Extension upload successful!
Extension dist/custom_my-extension-0.0.1.zip uploaded to https://<your_environment_url_here>/
Documentation¶
Extension
Extension.logger
Extension.schedule_decorators
Extension.is_helper
Extension.task_id
Extension.monitoring_config_id
Extension.run()
Extension.on_shutdown()
Extension.schedule()
Extension.query()
Extension.initialize()
Extension.fastcheck()
Extension.register_fastcheck()
Extension.report_metric()
Extension.report_mint_lines()
Extension.report_event()
Extension.report_dt_event()
Extension.report_dt_event_dict()
Extension.report_log_event()
Extension.report_log_events()
Extension.report_log_lines()
Extension.enabled_feature_sets
Extension.enabled_feature_sets_names
Extension.enabled_feature_sets_metrics
Extension.get_version()
Extension.techrule
Extension.get_activation_config()
Extension.get_snapshot()
- Events
- Metrics