Code Monkey home page Code Monkey logo

oneagent-sdk-for-python's Introduction

Read the latest version of this README, with working internal links, at GitHub.

Dynatrace OneAgent SDK for Python

This SDK enables Dynatrace customers to extend request level visibility into Python applications. It provides the Python implementation of the Dynatrace OneAgent SDK.

For the latest updates, see Release notes and announcements and make sure you are reading the latest version of this document.

Requirements

The latest release of the SDK supports Python 3 only, see below for exact support status of Python versions.

Only the official CPython (that is, the "normal" Python, i.e. the Python implementation from https://python.org) is supported and only on Linux (musl libc which is used, e.g., on Alpine Linux, is currently not supported) and Windows with the x86 (including x86-64) architecture. It is always advised to use the latest patch version of your minor versoin of Python, as these usually contain security fixes and other important bugfixes.

Additionally, pip with the wheel and setuptools package installed is required for installation, and on Linux, the system needs to be manylinux1-compatible. pip versions before 8.1.0 are known not to work, but generally it is advised to always use the latest pip version. Due to factors such as changes in package hosting by PyPI and Python itself, Dynatrace cannot guarantee that SDK installation is, or will continue to be, possible with old pip versions.

The Dynatrace OneAgent SDK for Python is a wrapper of the Dynatrace OneAgent SDK for C/C++ and therefore the SDK for C/C++ is required and delivered with the Python SDK. See here for its requirements, which also apply to the SDK for Python.

The version of the SDK for C/C++ that is included in each version of the SDK for Python is shown in the following table along with the required Dynatrace OneAgent version (it is the same as listed in the OneAgent SDK for C/C++'s documentation).

Note: The OneAgent SDK is not supported on serverless code modules, including those for AWS Lambda. Consider using OpenTelemetry instead in these scenarios.

OneAgent SDK for Python Bundled OneAgent SDK for C/C++ Required OneAgent Required Python Support status
1.5.x 1.7.1 ≥1.251 ≥3.5 🟢 Supported
1.4.x 1.6.1 ≥1.179 3.4.x-3.11.x ℹ️ Deprecated with support ending 2024-06-01
1.3.x 1.5.1 ≥1.179 2.7.x or 3.4.x-3.11.x ❌ Unsupported since 2023-07-01
1.2.x 1.4.1 ≥1.161 2.7.x or 3.4.x-3.11.x ❌ Unsupported since 2023-07-01
1.1.x 1.3.1 ≥1.151 2.7.x or 3.4.x-3.11.x ❌ Unsupported since 2023-07-01
1.0.x 1.1.0 ≥1.141 2.7.x or 3.4.x-3.11.x ❌ Unsupported since 2023-07-01

Note that this table only states the support status of the mentioned OneAgent SDK for Python version with the included OneAgent SDK for C/C++, not the OneAgent itself.

The "required Python" column indicates the Python versions with which the SDK version was developed and tested (where marked with *, the minimum version has been updated to adjust for Python deprecations from the table below). We may additionally announce deprecations for older versions of Python in combination with specific or all versions of the SDK, meaning that we will no longer provide support for these combinations after the given date, even if the SDK version itself is supported and technically running on that Python version. We also strongly advise against using Python versions that are no longer supported by your Python vendor.

We intend to deprecate Python versions effective around 6 months after the Python project stops supporting them as documented by the Python project: https://devguide.python.org/versions/. We will announce every deprecation explicitly, usually 6 months before it becomes effective.

Python version Deprecation status
Any later 3.x 🟢 Supported unless announced otherwise. Pre-releases are not supported.
3.8.x 🟢 Supported. Expected to be deprecated with support ending around May 2025
3.7.x ⚠️ Deprecated with SDK support ending 2024-09-01; Declared EOL by Python.org
3.4.x-3.6.x ⚠️ Deprecated with SDK support (with compatible SDK versions) ending 2024-06-01; Declared EOL by Python.org
2.7.x ❌ Unsuspported since 2023-07-01

Using the OneAgent SDK for Python in your application

To install the latest version of the OneAgent SDK for Python, use the PyPI package oneagent-sdk:

python -m pip install --upgrade oneagent-sdk

pip, setuptools and wheel need to be installed and should be up to date before running this command.

To verify your installation, execute

python -c "import oneagent; print(oneagent.initialize())"

If the installation was successful, you should get an output ending with InitResult(status=0, error=None). Otherwise, see the Troubleshooting section.

To load the OneAgent SDK into your application, just add the following line at the top of your script:

import oneagent

Here is a quick "Hello World" that will produce a service call in Dynatrace:

import oneagent

if not oneagent.initialize():
    print('Error initializing OneAgent SDK.')

with oneagent.get_sdk().trace_incoming_remote_call('method', 'service', 'endpoint'):
    pass

print('It may take a few moments before the path appears in the UI.')
input('Please wait...')
oneagent.shutdown()

A more detailed sample application is available here. See also the Quickstart section in the API documentation.

API Concepts

Common concepts of the Dynatrace OneAgent SDK are explained in the Dynatrace OneAgent SDK repository.

Initialization and SDK objects

Before first using any other SDK functions, you need to initialize the SDK.

init_result = oneagent.initialize()
print('OneAgent SDK initialization result' + repr(init_result))
if init_result:
    print('SDK should work (but agent might be inactive).')
else:
    print('SDK will definitely not work (i.e. functions will be no-ops):', init_result)

See the API documentation for the initialize function and the InitResult class for more information.

To use the SDK, get a reference to the SDK singleton by calling the oneagent static get_sdk method. The first thing you may want to do with this object, is checking if the agent is active by comparing the value of the agent_state property to the oneagent.common.AgentState constants. You can also have a look at the extended SDK state information.

import oneagent
from oneagent.common import AgentState
# Initialize oneagent, as above

sdk = oneagent.get_sdk()
if sdk.agent_state not in (AgentState.ACTIVE, AgentState.TEMPORARILY_INACTIVE):
    print('Too bad, you will not see data from this process.')

As a development and debugging aid it is recommended to set a diagnostic callback. The callback will be used by the SDK to inform about unusual events.

Unusual events that prevent an operation from completing successfully include:

  • API usage errors
  • other unexpected events (like out of memory situations)

NOTE: Use this as a development and debugging aid only. Your application should not rely on a calling sequence or any message content being set or passed to the callback.

During development, it is additionally recommended to use the "verbose callback" which also informs about other events that may be benign but can be very helpful in debugging, e.g. a PurePath that was not created because a Tracer is disabled by configuration, etc.

def _diag_callback(unicode_message):
	print(unicode_message)

sdk.set_diagnostic_callback(_diag_callback)
sdk.set_verbose_callback(_diag_callback) # Do not use this callback in production

Tracers

To trace any kind of call you first need to create a Tracer, using one of the various trace_* methods of the SDK object. The Tracer object controls the “life cycle” of a trace: Entering a with-block with a tracer starts the trace, exiting it ends it. Exiting the with block with an exception causes the trace to be marked as failed with the exception message (if you do not want or need this behavior, tracers have explicit methods for starting, ending and attaching error information too; see the documentation).

A Tracer instance can only be used from the thread on which it was created. Whenever you start a tracer, the tracer becomes a child of the previously active tracer on this thread and the new tracer then becomes the active tracer. You may only end the active tracer. If you do, the tracer that was active before it (its parent) becomes active again. Put another way, tracers must be ended in reverse order of starting them (you can think of this being like HTML tags where you must also close the child tag before you can close the parent tag). While the tracer's automatic parent-child relationship works very intuitively in most cases, it does not work with asynchronous patterns, where the same thread handles multiple logically separate operations in an interleaved way on the same thread. If you need to instrument such patterns with the SDK, you need to end your tracer before the thread is potentially reused by any other operation (e.g., before yielding to the event loop). To later continue the trace, capture an in-process link before and later resume using the in-process link tracer, as explained in Trace in-process asynchronous execution. This approach is rather awkward and may lead to complex and difficult to interpret traces. If your application makes extensive use of asynchronous patterns of the kind that is difficult to instrument with the SDK, consider using the OpenTelemetry support of Dynatrace instead.

There are different tracer types requiring different information for creation. As an example, to trace an incoming remote call, this would be the most simple way to trace it:

import oneagent

with oneagent.get_sdk().trace_incoming_remote_call('method', 'service', 'endpoint'):
    pass # Here you would do the actual work that is timed

See the section on remote calls for more information.

Some tracers also support attaching additional information before ending it.

Important: In Python 2, tracers accept both byte (“normal”) and unicode strings. Byte strings must always use the UTF-8 encoding!

Features and how to use them

The feature sets differ slightly with each language implementation. More functionality will be added over time, see Planned features for OneAgent SDK for details on upcoming features.

A more detailed specification of the features can be found in Dynatrace OneAgent SDK.

Feature Required OneAgent SDK for Python version
W3C trace context for log enrichment ≥1.5.0
Custom services ≥1.2.0
Messaging ≥1.2.0
In-process linking ≥1.1.0
Custom request attributes ≥1.1.0
Outgoing web requests ≥1.1.0
Incoming web requests ≥1.0.0
SQL database requests ≥1.0.0
Trace incoming and outgoing remote calls ≥1.0.0

Remote calls

You can use the SDK to trace communication from one process to another. This will enable you to see full Service Flow, PurePath and Smartscape topology for remoting technologies that Dynatrace is not aware of.

To trace any kind of remote call you first need to create a Tracer. The Tracer object represents the endpoint that you want to call, thus you need to supply the name of the remote service and method. In addition, you need to transport a tag in your remote call from the client side to the server side if you want to trace it end to end.

On the client side, you would trace the outgoing remote call like this:

outcall = sdk.trace_outgoing_remote_call(
    'remoteMethodToCall', 'RemoteServiceName', 'rmi://Endpoint/service',
    oneagent.sdk.Channel(oneagent.sdk.ChannelType.TCP_IP, 'remoteHost:1234'),
    protocol_name='RMI/custom')
with outcall:
    # Note: You can access outgoing_dynatrace_*_tag only after the trace
    # has started!
    strtag = outcall.outgoing_dynatrace_string_tag
    do_actual_remote_call(extra_headers={'X-dynaTrace': strtag})

On the server side, you would trace it like this:

incall = sdk.trace_incoming_remote_call(
    'remoteMethodToCall', 'RemoteServiceName', 'rmi://Endpoint/service',
    protocol_name='RMI/custom',
    str_tag=my_remote_message.get_header_optional('X-dynaTrace'))
with incall:
    pass # Here you would do the actual work that is timed

See the documentation for more information:

SQL database requests

To trace database requests you need a database info object which stores the information about your database which does not change between individual requests. This will typically be created somewhere in your initialization code (after initializing the SDK):

dbinfo = sdk.create_database_info(
    'Northwind', oneagent.sdk.DatabaseVendor.SQLSERVER,
    oneagent.sdk.Channel(oneagent.sdk.ChannelType.TCP_IP, '10.0.0.42:6666'))

Then you can trace the SQL database requests:

with sdk.trace_sql_database_request(dbinfo, 'SELECT foo FROM bar;') as tracer:
    # Do actual DB request
    tracer.set_rows_returned(42) # Optional
    tracer.set_round_trip_count(3) # Optional

Note that you need to release the database info object. You can do this by calling close() on it or using it in a with block.

See the documentation for more information:

Please note that SQL database traces are only created if they occur within some other SDK trace (e.g. incoming remote call).

Incoming web requests

Same as with database infos, to trace incoming web requests you need a web application info object which stores the information about your web application which does not change:

wappinfo = sdk.create_web_application_info(
    virtual_host='example.com',
    application_id='MyWebApplication',
    context_root='/my-web-app/')

Then you can trace incoming web requests:

wreq = sdk.trace_incoming_web_request(
    wappinfo,
    'http://example.com/my-web-app/foo?bar=baz',
    'GET',
    headers={'Host': 'example.com', 'X-foo': 'bar'},
    remote_address='127.0.0.1:12345')

with wreq:
    wreq.add_parameter('my_form_field', '1234')
    # Process web request
    wreq.add_response_headers({'Content-Length': '1234'})
    wreq.set_status_code(200) # OK

Note that you need to release the web application info object. You can do this by calling close() on it or using it in a with block.

Incoming web request tracers support some more features not shown here. Be sure to check out the documentation:

Outgoing web requests

To trace an outgoing web request you need to create an 'Outgoing Web Request Tracer' object. You pass the destination URL, the HTTP method and request headers as parameters.

Let's have a look at a web request example:

from urllib.request import Request

# Create your web request.
url = 'http://example.com'

req = Request(url)
req.add_header('header1', '1234')
req.add_header('header2', '5678')

After creating/setting up the request you have to create the tracer object and pass the parameters.

# Create the tracer.
tracer = sdk.trace_outgoing_web_request(url, req.get_method(), req.headers)

The next step is to start the tracer and then to retrieve the outgoing Dynatrace tag. The tag is being used to trace a transaction from end-to-end. You have to send the tag to the destination via an additional request header which is called DYNATRACE_HTTP_HEADER_NAME. Here you can find more information on tagging.

with tracer:
	# Get and set the Dynatrace tag.
	tag = tracer.outgoing_dynatrace_string_tag
 	req.add_header(DYNATRACE_HTTP_HEADER_NAME, tag)

	# Here you process and send the web request.
	response = _process_your_outgoing_request(req)

Finally, get the response headers you want to trace and the status code of the response and add them to the tracer.

        tracer.add_response_headers({'Content-Length': response.get_content_length()})
        tracer.set_status_code(response.get_status_code())

Be sure to check out the documentation:

Trace in-process asynchronous execution

You can use the SDK to trace asynchronous in-process code execution. This might be useful if the OneAgent does not support the threading framework or specific asynchronous libraries. In-process linking should be used to link other services (Database, Webrequests, ...) between thread or queueing boundaries currently not supported out-of-the-box by the OneAgent.

To link asynchronous execution, you need to create an in-process link, where the execution forks:

in_process_link = sdk.create_in_process_link()

The provided in-process link must not be serialized and can only be used inside the process in which it was created. It must be used to start tracing where the asynchronous execution takes place:

with sdk.trace_in_process_link(in_process_link):
 	# Do the asynchronous job
 	:

Custom Request Attributes

You can use the SDK to add custom request attributes to the currently traced service. Custom request attributes allow you to do easier/better filtering of your requests in Dynatrace.

Adding custom request attributes to the currently traced service call is pretty simple. Just call the add_custom_request_attribute method with your key and value (only int, float and string values are currently supported):

sdk.add_custom_request_attribute('errorCount', 42)
sdk.add_custom_request_attribute('gross weight', 2.39)
sdk.add_custom_request_attribute('famous actor', 'Benedict Cumberbatch')

Check out the documentation at:

Custom services

You can use the SDK to trace custom service methods. A custom service method is a meaningful part of your code that you want to trace but that does not fit any other tracer. An example could be the callback of a periodic timer.

with sdk.trace_custom_service('onTimer', 'CleanupTask'):
	# Do the cleanup task

Check out the documentation at:

Messaging

You can use the SDK to trace messages sent or received via a messaging system. When tracing messages, we distinguish between:

  • sending a message
  • waiting for and receiving a message
  • processing a received message

Outgoing Messages

All messaging related tracers need a messaging system info object which you have to create prior to the respective messaging tracer, which is an outgoing message tracer in the example below.

msi_handle = sdk.create_messaging_system_info(
	'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
	oneagent.sdk.Channel(oneagent.sdk.ChannelType.TCP_IP, '10.11.12.13'))

with msi_handle:
	with sdk.trace_outgoing_message(msi_handle) as tracer:
		# Get and set the Dynatrace tag.
		tag = tracer.outgoing_dynatrace_string_tag
		message_to_send.add_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME, tag)

		# Send the message.
		the_queue.send(message_to_send)

		# Optionally set message and/or correlation IDs
		tracer.set_vendor_message_id(message_to_send.get_message_id())
		tracer.set_correlation_id(message_to_send.get_correlation_id())

Incoming Messages

On the incoming side, we need to differentiate between the blocking receiving part and processing the received message. Therefore two different tracers are being used:

  • IncomingMessageReceiveTracer
  • IncomingMessageProcessTracer
msi_handle = sdk.create_messaging_system_info(
	'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
	oneagent.sdk.Channel(oneagent.sdk.ChannelType.TCP_IP, '10.11.12.13'))

with msi_handle:
	# Create the receive tracer for incoming messages.
	with sdk.trace_incoming_message_receive(msi_handle):
		# This is a blocking call, which will return as soon as a message is available.
		Message query_message = the_queue.receive()

		# Get the Dynatrace tag from the message.
		tag = query_message.get_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME)

		# Create the tracer for processing incoming messages.
		tracer = sdk.trace_incoming_message_process(msi_handle, str_tag=tag)
		tracer.set_vendor_message_id(query_message.get_vendor_id())
		tracer.set_correlation_id(query_message.get_correlation_id())

		with tracer:
			# Now let's handle the message ...
			print('handle incoming message')

In case of non-blocking receive (e. g. using an event handler), there is no need to use an IncomingMessageReceiveTracer - just trace processing of the message by using the IncomingMessageProcessTracer:

msi_handle = sdk.create_messaging_system_info(
	'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
	oneagent.sdk.Channel(oneagent.sdk.ChannelType.TCP_IP, '10.11.12.13'))

def on_message_received(message):
	# Get the Dynatrace tag from the message.
	tag = message.get_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME)

	# Create the tracer for processing incoming messages.
	tracer = sdk.trace_incoming_message_process(msi_handle, str_tag=tag)
	tracer.set_vendor_message_id(message.get_vendor_id())
	tracer.set_correlation_id(message.get_correlation_id())

	with tracer:
		# Now let's handle the message ...
		print('handle incoming message')

See the documentation for more information:

W3C trace context

This feature allows you to retrieve a W3C TraceContext trace ID and span ID referencing the current PurePath node, as defined in https://www.w3.org/TR/trace-context.

This trace ID and span ID information is not intended for tagging and context-propagation scenarios and primarily designed for log-enrichment use cases. Refer to General information on tagging for tagging traces (see also the usage examples elsewhere in this document).

The following example shows how to print the current trace & span ID to stdout in a format that works well with Dynatrace Log Monitoring (see https://www.dynatrace.com/support/help/shortlink/log-monitoring-log-enrichment for more):

with sdk.trace_custom_service('onTimer', 'CleanupTask'): # Or any other tracer
	tinfo = sdk.tracecontext_get_current()
	print('[!dt dt.trace_id={},dt.span_id={}] handle incoming message'.format(tinfo.trace_id, tinfo.span_id))

See the documentation for more information:

Using the OneAgent SDK for Python with forked child processes (only available on Linux)

Some applications, especially web servers, use a concurrency model that is based on forked child processes. Typically a master process is started which is responsible only for creating and managing child processes by means of forking. The child processes do the real work, for example handling web requests.

The recommended way to use the Python SDK in such a scenario is as follows: You initialize the SDK in the master process setting the forkable argument to True.

oneagent.initialize(sdk_options, forkable=True)

This way you will not be able to use the SDK in the master process (attempts to do so will be ignored, if applicable with an error code), but all forked child processes will share the same agent. This has a lower overhead, for example the startup of worker processes is not slowed down, and the per-worker memory overhead is reduced.

For more information on forked child processes, take a look at those resources:

Troubleshooting

To debug your OneAgent SDK for Python installation, execute the following Python code:

import logging
import time
import oneagent

log_handler = logging.StreamHandler()
log_formatter = logging.Formatter(
    '%(asctime)s.%(msecs)03d UTC [%(thread)08x]'
    ' %(levelname)-7s [%(name)-6s] %(message)s',
    '%Y-%m-%d %H:%M:%S')
log_formatter.converter = time.gmtime
log_handler.setFormatter(log_formatter)
oneagent.logger.addHandler(log_handler)
oneagent.logger.setLevel(1)
init_result = oneagent.initialize(['loglevelsdk=finest', 'loglevel=finest'])
print('InitResult=' + repr(init_result))

If you get output containing InitResult=InitResult(status=0, error=None), your installation should be fine. Otherwise, the output is helpful in determining the issue. The extended SKD state might also help to diagnose your problem.

Known gotchas:

  • ImportError or ModuleNotFoundError in line 1 that says that there is no module named oneagent.

    Make sure that the pip install or equivalent succeeded (see here). Also make sure you use the pip corresponding to your python (if in doubt, use python -m pip instead of pip for installing).

  • Output ending in a message like InitResult=InitResult(status=-2, error=SDKError(-1342308345, 'Failed loading SDK stub from .../site-packages/oneagent/_impl/native/libonesdk_shared.so: "/.../libonesdk_shared.so: cannot open shared object file: No such file or directory". Check your installation of the oneagent-sdk Python package, e.g., try running pip install --verbose --force-reinstall oneagent-sdk.')).

    Follow the advice of the message and run python -m pip install --verbose --force-reinstall oneagent-sdk (or the equivalent pip invocation with the --verbose and --force-reinstall flags). It is likely that you will now see another message like

      ******************************************************************************
      *** You are trying to build the Python SDK from source.                    ***
      *** This could mean that you are using an outdated version of pip (older   ***
      *** than 8.1.0) or you are attempting to install the SDK on an             ***
      *** unsupported platform. Please check the requirements at                 ***
      *** https://github.com/Dynatrace/OneAgent-SDK-for-Python#requirements      ***
      ******************************************************************************
    

    Make sure you are using pip to install a prebuilt package wheel for your system from PyPI, as described in Using the OneAgent SDK for Python in your application. Also make sure you are using an up-to date version of pip, setuptools and wheel. You can try upgrading them with python -m pip install --upgrade pip setuptools wheel (make sure to use the same python that you use to install the oneagent-sdk package). ATTENTION: If you use the system-provided pip (e.g. installed via apt-get on Ubuntu) you should instead use a pip inside a virtualenv (the same as your project), as upgrading system-provided packages via pip may cause issues.

    If this does not resolve the issue, make sure you are using a supported platform, as listed in Requirements. If you are using a supported system, you can try downloading the OneAgent SDK for C/C++ in the version corresponding to your OneAgent SDK for Python as listed in the table in Requirements. Then set the DT_PYSDK_CSDK_PATH environment variable to the .so/.dll file corresponding to your platform in the lib subdirectory of the C SDK and retry the installation (e.g. in a bash shell, use export DT_PYSDK_CSDK_PATH=path/to/onesdk_shared.so). If there is no corresponding directory, your platform is not supported. Otherwise, regardless if it works with that method or not, please report an issue as described in Let us help you.

Extended SDK State

For debugging and/or diagnosing purposes you can also use the extended SDK state information.

# The agent state is one of the integers in oneagent.sdk.AgentState.
print('Agent state:', oneagent.get_sdk().agent_state)

# The instance attribute 'agent_found' indicates whether an agent could be found or not.
print('Agent found:', oneagent.get_sdk().agent_found)

# If an agent was found but it is incompatible with this version of the SDK for Python
# then 'agent_is_compatible' would be set to false.
print('Agent is compatible:', oneagent.get_sdk().agent_is_compatible)

# The agent version is a string holding both the OneAgent version and the
# OneAgent SDK for C/C++ version separated by a '/'.
print('Agent version:', oneagent.get_sdk().agent_version_string)

Shutdown crashes

If your are experiencing crashes when your application exits, make sure you uninitialized the SDK properly by calling its shutdown function.

Repository contents

If you are viewing the GitHub repository, you will see:

  • LICENSE: License under which the whole SDK and sample applications are published.
  • src/: Actual source code of the Python OneAgent SDK.
  • docs/: Source files for the (Sphinx-based) HTML documentation. For the actual, readable documentation, see here.
  • tests/, test-util-src/: Contains tests and test support files that are useful (only) for developers wanting to contribute to the SDK itself.
  • setup.py, setup.cfg, MANIFEST.in, project.toml: Development files required for creating e.g. the PyPI package for the Python OneAgent SDK.
  • tox.ini, pylintrc: Supporting files for developing the SDK itself. See https://tox.readthedocs.io/en/latest/ and https://www.pylint.org/.

Help & Support

Support policy

The Dynatrace OneAgent SDK for Python has GA status. The features are fully supported by Dynatrace.

For detailed support policy see Dynatrace OneAgent SDK help.

Read the manual

Let us help you

Make sure your issue is not already solved in the available documentation before you ask for help. Especially the troubleshooting section in this README may prove helpful.

Get Help

Open a GitHub issue to:

  • Report minor defects or typos.
  • Ask any questions related to the community effort.

SLAs don't apply for GitHub tickets.

Customers can open a ticket on the Dynatrace support portal to:

  • Get support from the Dynatrace technical support engineering team
  • Manage and resolve product related technical issues

SLAs apply according to the customer's support level.

Release notes and announcements

For additional updates, see also OneAgent release notes and End of support announcements.

Announcements in November 2023

  • ⚠️ Deprecation announcement for older SDK versions: Version 1.4 has been put on the path to deprecation and will no longer be supported starting June 1, 2024. Only version 1.5 of the SDK (or any newer version) will be supported from that date on.
  • ⚠️ Deprecation announcement for using any SDK version with older Python versions: SDK support for Python 3.4.x, 3.5.x, 3.6.x and 3.7.x has been put on the path to deprecation and no version of the SDK will be supported on Python 3.4.x, 3.5.x and 3.6.x starting June 1, 2024. Usage of the SDK on 3.7.x will remain supported until September 1, 2024. All Python versions below 3.8.x are already declared End of Life by the Python.org project, and customers are encouraged to upgrade to a newer Python version that is also supported by Python.org.

Version 1.5.1

Changes:

  • Fixes support of Python 3.12 and newer

Version 1.5.0

Changes:

  • Adds limited W3C trace context support (for log enrichment).
  • This version no longer supports Python 2 (Python 2.7.x).
  • This version no longer supports Python 3.4.x.

Announcements:

  • ⚠️ Deprecation announcement for older SDK versions: Version 1.3 and all older versions have been put on the path to deprecation and will no longer be supported starting July 1, 2023. We strongly advise customers to upgrade to newest versions to avoid incompatibility and security risks. Customers need to upgrade to at least 1.4 but are encouraged to upgrade to the newest available version (1.5) if using Python >3.4 as there are no known incompatibilities or breaking changes other than the increased minimum Python version.
  • ⚠️ Deprecation announcement for using any SDK version with older Python versions: Python 2.7.x has been put on the path to deprecation and no version of the SDK will be supported on this Python version starting July 1, 2023. Furthermore, we intend to release a similar deprecation announcement regarding versions 3.4-3.6 (which are no longer maintained by the Python project) soon (we plan that this will not become effective before 2023-07-01).

See https://github.com/Dynatrace/OneAgent-SDK-for-Python/releases for older releases.

License

See the LICENSE file for details. It should be included in your distribution. Otherwise, see the most recent version on GitHub.

Summary: This software is licensed under the terms of the Apache License Version 2.0 and comes bundled with the six library by Benjamin Peterson, which is licensed under the terms of the MIT license.

oneagent-sdk-for-python's People

Contributors

alramlechner avatar arminru avatar cgdt avatar hiteshbedre avatar mikopp avatar oberon00 avatar z1c0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oneagent-sdk-for-python's Issues

Trace Context - Missing func oneAgentSDK.getTraceContextInfo in order to fetch Span_Id and Trace_id

Contrary to Java SDK, Python OneAgent SDK do not provides access to TraceContextInfo which holds information about the Trace-Id and Span-Id of the current PurePath node.

Could you add functions which do the same call as Java SDK (missing funcs: TraceContextInfo, getTraceId, getSpanId)?

NOTE: The java code documentation is accessible thought this url tag https://github.com/Dynatrace/OneAgent-SDK/blob/master/README.md#trace-context.

Agent does not seem to trace calls to MongoDB when using AsyncIOMotorClient.

I wonder if anyone out there managed to get Dynatrace to work with AsyncIOMotorClient, like when we use Beanie.
It seems that in the Listener the oneage.get_sdk().tracecontext_get_current() is always empty, it's like OneAgent loses track of the current trace context.
It seems that the python SDK does not support the scenario where we use MongoDb with Beanie.

Have you guys also seen this?

Add Python code-level visibility via SDK

Hi,

Currently we see the following code level details after instrumenting our API endpoints with the Python SDK: https://1drv.ms/u/s!AtRjMrJnRHluhaxt7nQJ68lInccqNg

We were wondering if there is a way (using the SDK) to add more information on the actual Python functions that are invoked when processing this API call and how long each Python function takes.

We don't want to create additional Service objects (with the Custom tracer functionality). We want to add code-level details within the current Service object.

Is this already possible? Or is this a feature on the roadmap?

More transparent active tracer / add_custom_request_attribute

Hi, I would like to ask some more transparency for tracer handling. The add_custom_request_attribute function requires an active tracer to succeed. Unfortunately, until now there is no way to check if it succeeded or failed. Applications need to keep track on tracers explicitly, which is error-prone. As a quick-fix it would suffice if add_custom_request_attribute returns a Boolean value or an error code. Alternative and more general solution is to offer access to the active tracer object.

Getting 3 different errors (-2, -1, and 2) when initialize an agent

Hi,

I am getting three different errors when I run from a command line, when I initialize an agent inside a python script and when I run the command on a Mac (as opposed to Linux):

Command line:

$ python -c "import oneagent; print(oneagent.initialize())"
InitResult(status=-1, error=SDKError(-1342308345, 'onesdk_initialize_2: Could not load agent.'))

Python script

>> import oneagent
>> oneagent.initialize()
InitResult(status=2, error=None)

On Mac (no matter how many times I force to re-install):

InitResult(status=-2, error=SDKError(-1342308345, 'Failed loading SDK stub from /Users/mnosrat/Projects/miniconda3/lib/python3.7/site-packages/oneagent/_impl/native/libonesdk_shared.so: "dlopen(/Users/mnosrat/Projects/miniconda3/lib/python3.7/site-packages/oneagent/_impl/native/libonesdk_shared.so, 6): image not found". Check your installation of the oneagent-sdk Python package, e.g., try running `pip install --verbose --force-reinstall oneagent-sdk`.'))

Any idea how I can fix this?
Thanks a lot

Upcoming deprecation for SDK 1.4 and Python 3.4, 3.5, 3.6, 3.7

To rise awareness for https://github.com/Dynatrace/OneAgent-SDK-for-Python/tree/master#release-notes-and-announcements:


For additional updates, see also OneAgent release notes and End of support announcements.

Announcements in November 2023

  • ⚠️ Deprecation announcement for older SDK versions: Version 1.4 has been put on the path to deprecation and will no longer be supported starting June 1, 2024. Only version 1.5 of the SDK (or any newer version) will be supported from that date on.
  • ⚠️ Deprecation announcement for using any SDK version with older Python versions: SDK support for Python 3.4.x, 3.5.x, 3.6.x and 3.7.x has been put on the path to deprecation and no version of the SDK will be supported on Python 3.4.x, 3.5.x and 3.6.x starting June 1, 2024.
    Usage of the SDK on 3.7.x will remain supported until September 1, 2024.
    All Python versions below 3.8.x are already declared End of Life by the Python.org project, and customers are encouraged to upgrade to a newer Python version that is also supported by Python.org.

Multiple tracers per thread: allowed?

Hello! I've read in the documentation that tracer should be started and ended by the same thread. However, I am wondering if one thread can start and end multiple tracers of the same type? I am getting errors in my service and I am questioning if that could be the reason why.

I am using FastAPI web framework where one thread handles multiple incoming web requests concurrently (it switches between request whenever one of the requests needs to wait on something). Whenever new requests comes in, incoming web request tracer is started, and on completion tracer is ended. Thus, it could be the case that the same thread starts multiple tracers and closes them in an undefined order. For example, thread could execute tracer-related statements in this order:

tracer1.start
tracer2.start
tracer1.end
tracer3.start
tracer2.end
tracer3.end

The errors I am seeing in my application logs are the following:

2020-11-02 19:16:38,283  [ERROR] MainThread - NOTE: Marking sub-path as broken. Reason: unexpected error while trying to exit (end) a node - see following messages.
2020-11-02 19:16:38,283  [ERROR] MainThread - Removing path. Reason: broken.
2020-11-02 19:16:38,283  [ERROR] MainThread - WARNING: Wrong node state: in 'onesdk_tracer_end'(IncomingWebRequest): cannot exit a node that isn't top-of-stack.

And the matching agent logs:

2020-11-02 19:16:38.283 UTC warning [native] PATH  EXEC  tagId(737807) sensorId(102) HPurePath(0x0000421b00000001) inconsistency (MethodExitMissing): Path ended, but current method node misses exit call NODE: SDK Method depth(1) serialNo(188878636) unused(FALSE) aggr[excl(FALSE) info(FALSE) root(FALSE) fin(FALSE)] method[0x48ad19521e8c01af,OneAgent SDK.Incoming web request, cat=WebRequest, art(TRUE)] contentChged(TRUE) Attachments(WebRequestAttachment ) 
2020-11-02 19:16:38.283 UTC info    [native] WARNING: Wrong node state: in 'onesdk_tracer_end'(IncomingWebRequest): cannot exit a node that isn't top-of-stack.

It would be helpful to know whether it is a right way or not to use tracers like that (one thread with multiple tracers).

support for gunicorn workers

I would like to initialize the SDK once at the main application before my workers are spawned and have the SDK trace calls made by the workers. Currently, I have to initialize the SDK inside each worker, which gets complicated as to how many SDK instances I have running/shutdown.

Incomplete traces with diagnostic message "Some data could not be collected or transmitted. " with asynchronous calls

Description:
When transitioning a FastAPI service to asynchronous calls, we encountered an issue with Dynatrace tracing. Previously, in synchronous mode, traces were complete without any missing information. However, after switching to asynchronous calls, some traces contain the diagnostic message

Some data could not be collected or transmitted. This is most likely due to a resource congestion on network, host or process level in your monitored environment. (Error code: C1)

these traces lack some information like custom request attributes, status code, response time.

Details:

  • The service is instrumented with the OneAgent SDK for Dynatrace.
  • Same issue occurs with autodynatrace package https://github.com/dynatrace-oss/OneAgent-SDK-Python-AutoInstrumentation which internally uses OneAgent
  • Dynatrace operates within a middleware.
  • Attempts to address the problem using the in_process_link code snippet, as suggested in the documentation, have been made but with no success.
  • While testing with lower request loads, the tracing behaves as expected. However, under higher loads where a single process handles multiple asynchronous requests, the issue becomes apparent.

Code Snippet:

async def handle_post_async(data, request, handler):

    app_info = self.__get_app_info(request)
    tag = request.headers.get(oneagent.common.DYNATRACE_HTTP_HEADER_NAME)
    sdk = oneagent.get_sdk()
    link = sdk.create_in_process_link()
    with sdk.trace_in_process_link(link):
        with sdk.trace_incoming_web_request(app_info,
                                            str(request.url),
                                            request.method,
                                            str_tag=tag) as tracer:

            try:
                def trace_params(params: {}):
                    tracer.add_parameters(params)

                request.state.tracer = trace_params

                result = await handler(data, request)
                response = make_response(result)
                tracer.set_status_code(response.status_code)
            except Exception as e:
                type = e.__class__.__name__
                if type == 'BadRequest':
                    response = self.create_error_response(str(e), 400, request, logging.WARNING)
                elif type == 'ValueError':
                    response = self.create_error_response(str(e), 400, request, logging.ERROR)
                else:
                    response = self.create_error_response(str(e), 500, request, logging.ERROR)

                tracer.set_status_code(response.status_code)

        return response

Expected Behavior:
Traces in Dynatrace should contain all necessary custom request attributes and response time information consistently, regardless of the request load or asynchronous nature of the service.

Got SDKError(2952658951) when initializing SDK OneAgent for Python

I am running Windows 11, python 3.10.5 on a pc with x64-based processor. Running the code to debug OneAgent i got this:

2022-10-04 15:13:31.854 UTC [00004068] info [onesdk] Could not load agent module for Dynatrace OneAgent SDK for C/C++: Loading via the process module failed and no fallback path was provided.
2022-10-04 15:13:31.858 UTC [00004068] ERROR [py_sdk] Failed initializing agent.
Traceback (most recent call last):
File "C:\Users\niorl\AppData\Local\Programs\Python\Python310\lib\site-packages\oneagent_init_.py", line 296, in _try_init_noref
nativeagent.checkresult(sdk, sdk.initialize(flags), 'onesdk_initialize_2')
File "C:\Users\niorl\AppData\Local\Programs\Python\Python310\lib\site-packages\oneagent_impl\native\nativeagent.py", line 43, in checkresult
raise SDKError(error_code, msg + ': ' + emsg)
oneagent.common.SDKError: (2952658951, 'onesdk_initialize_2: Could not load agent.')
2022-10-04 15:13:31.860 UTC [00004068] WARNING [py_sdk] Continuing with stub-SDK only.
InitResult=InitResult(status=InitResult.STATUS_INIT_ERROR, error=SDKError(2952658951, 'onesdk_initialize_2: Could not load agent.'))

Python 3.12 or newer requires oneagent-sdk>=1.5.1

When trying to use OneAgent SDK on Python 3.12 or newer, you will encounter this error when using a SDK version older than 1.5.1:

>>> import oneagent
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.12/site-packages/oneagent/__init__.py", line 84, in <module>
    from oneagent._impl.six.moves import range #pylint:disable=import-error
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'oneagent._impl.six.moves'

You need to upgrade at least to oneagent-sdk>=1.51 for Python 3.12 support. While oneagent-sdk 1.4.x generally remains supported (until 2024-06-01), there are currently no plans to add Python 3.12 support to 1.4.x.


Note that if you enable logging for the Python SDK (for example as explained in the Troubleshooting section of the README), you may encounter a warning message similar to the following:

2024-01-04 10:48:01.767 UTC [7fc3553a4040] WARNING [py_sdk] Could not get native SDK path via pkg_resources: loading native SDK library might fail
Traceback (most recent call last):
  File ".../lib/python3.12/site-packages/oneagent/_impl/native/sdkctypesiface.py", line 797, in loadsdk
    import pkg_resources
ModuleNotFoundError: No module named 'pkg_resources'

This warning message is harmless and should be ignored. The cause is the removal of setuptools from default installations: python/cpython#95299. The SDK will fall back to calculating the path to load the native SDK shared library itself which typically works without any problems.

MacOS Support

It looks like a lot of the platform logic seems to exclude MacOS inside the setup.py. This causes issues when trying to install on a MacOS laptop.

For example, when I run

>>> from distutils.util import get_platform
>>> platform = get_platform()
>>> platform
'macosx-10.12-x86_64'

The lack of a "linux" starter throws off the logic.

Can you update your logic to allow for usage on Macs? Thanks

Documentation about how to monitor background processes

Is your feature request related to a problem? Please describe.

No article or guide describes how to instrument a job, consumer, or anything related. The competition has a document called monitor background processes and other non-web transactions, but none is available on Dynatrace. We've been trying to configure a consumer past few weeks without success. Our scenario:

Describe the solution you'd like

An official documentation from Dynatrace.

If we come up with a solution through this issue, I can write a blog post informing others how to monitor, including a complete project to download. People can use it as an example.

Describe alternatives you've considered

We're considering changing the company's ecosystem with more than 100 applications to the competition because what we're doing does not work.

Additional context

The following project has everything to mimic our scenario by running a Kubernetes locally:

https://github.com/MatheusGeiger/django-with-instrumentation

We have an open-source project with OpenTelemetry. It works like a charm, but the full set of features is not available. Dynatrace support recommended to use the SDK, so we had to abandon our library and focus on autodynatrace instead 😞.

https://github.com/juntossomosmais/opentelemetry-instrumentation-django-stomp

Out of the box tracing of web server endpoints

I would like to be able to initialize the SDK and have it automatically detect calls made to my web service framework's endpoints. Currently, I have to add the tracing calls to any function I want to trace. this makes sense if I want to trace functions deep inside my code, but for endpoint requests, I think it should just grab them automatically. This is how it works for IIS and other web services even without an SDK needed.

Path creation unsuccessful (incoming tag type: String) / Path creation unsuccessful (incoming tag type: Nothing).

I am unable to resolve this issue. Does anyone know what is causing this error. The following function onesdk_tracer_start'(IncomingWebRequest) was not invoked yet it is showing up as an error. Thank you.

2019-11-01 09:11:22.514 UTC [eb60a83e] info    [native] NOTE: No path available: in 'onesdk_tracer_start'(IncomingWebRequest): Path creation unsuccessful (incoming tag type: String).
2019-11-01 09:11:22.526 UTC [eb60a83e] info    [native] NOTE: No path available: in 'onesdk_tracer_start'(OutgoingWebRequest): Path creation unsuccessful (incoming tag type: Nothing).

Support for Python SDK for Alpine

Hello Dynatrace team,

Currently the SDK is not supported with Alpine. Alpine is used more and more for apps inside container.

It would be very nice to have it as currently we can't monitor some of our app because we use alpine as OS.

Any plan to support it ?

I have seen here. It is in "future" status : https://www.dynatrace.com/support/help/setup-and-configuration/dynatrace-oneagent/oneagent-technology-support/oneagent-platform-and-capability-support-matrix/

Thanks,
Alexandre

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.