Skip to content

Commit

Permalink
Merge pull request #5 from Dynatrace/prepare-1.2.0
Browse files Browse the repository at this point in the history
imported 1.2.0 changes
  • Loading branch information
cgdt authored May 16, 2019
2 parents f7b121b + 9e005e3 commit 36427c3
Show file tree
Hide file tree
Showing 13 changed files with 587 additions and 8 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ dist/
/tmp/
*.egg-info
.pytest_cache/
/.project
/.pydevproject
/.README.md.html
/.settings
124 changes: 123 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ This SDK enables Dynatrace customers to extend request level visibility into Pyt
* [Outgoing web requests](#outgoing-web-requests)
* [Trace in-process asynchronous execution](#trace-in-process-asynchronous-execution)
* [Custom request attributes](#custom-request-attributes)
* [Custom services](#custom-services)
* [Messaging](#messaging)
* [Outgoing Messages](#outgoing-messaging)
* [Incoming Messages](#incoming-messaging)
- [Troubleshooting](#troubleshooting)
* [Installation issues](#installation-issues)
* [Post-installation issues](#post-installation-issues)
Expand Down Expand Up @@ -54,6 +58,7 @@ Dynatrace OneAgent version (it is the same as
|:----------------------|:---------------------|:-----------------|
|1.0 |1.1.0 |≥1.141 |
|1.1 |1.3.1 |≥1.151 |
|1.2 |1.4.1 |≥1.161 |

<a name="#using-the-oneagent-sdk-for-python-in-your-application"></a>
## Using the OneAgent SDK for Python in your application
Expand Down Expand Up @@ -207,6 +212,8 @@ A more detailed specification of the features can be found in [Dynatrace OneAgen
|Outgoing web requests |≥1.1.0 |
|Custom request attributes |≥1.1.0 |
|In-process linking |≥1.1.0 |
|Messaging |≥1.2.0 |
|Custom services |≥1.2.0 |

<a name="remote-calls"></a>
### Remote calls
Expand Down Expand Up @@ -387,7 +394,7 @@ The provided in-process link must not be serialized and can only be used inside
tracing where the asynchronous execution takes place:

```python
with sdk.trace_in_process_link(in_process_link):
with sdk.trace_in_process_link(in_process_link):
# Do the asynchronous job
:
```
Expand All @@ -411,6 +418,121 @@ Check out the documentation at:
* [`add_custom_request_attribute`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.SDK.add_custom_request_attribute)


<a name="custom-services"></a>
### 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.

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

Check out the documentation at:
* [`trace_custom_service`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.SDK.trace_custom_service)


<a name="messaging"></a>
### 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

<a name="outgoing-messaging"></a>
#### 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.

```python
msi_handle = sdk.create_messaging_system_info(
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
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())
```

<a name="incoming-messaging"></a>
#### 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

```python
msi_handle = sdk.create_messaging_system_info(
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
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:

```python
msi_handle = sdk.create_messaging_system_info(
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
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:

* [`create_messaging_system_info`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.SDK.create_messaging_system_info)
* [`trace_outgoing_message`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_outgoing_message)
* [`trace_incoming_message_receive`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_incoming_message_receive)
* [`trace_incoming_message_process`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_incoming_message_process)
* [General information on tagging](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/tagging.html)


<a name="troubleshooting"></a>
## Troubleshooting

Expand Down
3 changes: 3 additions & 0 deletions docs/tagging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ The following classes are incoming-taggable:
:meth:`oneagent.sdk.SDK.trace_incoming_remote_call`
- :class:`IncomingWebRequestTracer` /
:meth:`oneagent.sdk.SDK.trace_incoming_web_request`
- :class:`IncomingMessageProcessTracer` /
:meth:`oneagent.sdk.SDK.trace_incoming_message_process`

The following classes are :class:`OutgoingTaggable`:

- :class:`OutgoingRemoteCallTracer`
- :class:`OutgoingWebRequestTracer`
- :class:`OutgoingMessageTracer`

You first use either :attr:`OutgoingTaggable.outgoing_dynatrace_string_tag` or
:attr:`OutgoingTaggable.outgoing_dynatrace_byte_tag` to retrieve a string or
Expand Down
57 changes: 57 additions & 0 deletions samples/basic-sdk-sample/basic_sdk_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import oneagent # SDK initialization functions
import oneagent.sdk as onesdk # All other SDK functions.

from oneagent.common import MessagingDestinationType


try: # Python 2 compatibility.
input = raw_input #pylint:disable=redefined-builtin
except NameError:
Expand Down Expand Up @@ -166,6 +169,9 @@ def mock_incoming_web_request():
# This call will trigger the diagnostic callback.
sdk.add_custom_request_attribute('another key', None)

# This call simulates incoming messages.
mock_process_incoming_message()

def _process_my_outgoing_request(_tag):
pass

Expand All @@ -190,6 +196,53 @@ def mock_outgoing_web_request():
tracer.add_response_headers({'Content-Length': '1234'})
tracer.set_status_code(200) # OK

def mock_process_incoming_message():
sdk = getsdk()

# Create the messaging system info object.
msi_handle = sdk.create_messaging_system_info(
'MyPythonSenderVendor', 'MyPythonDestination', MessagingDestinationType.QUEUE,
onesdk.Channel(onesdk.ChannelType.UNIX_DOMAIN_SOCKET, 'MyPythonChannelEndpoint'))

with msi_handle:
# Create the receive tracer for incoming messages.
with sdk.trace_incoming_message_receive(msi_handle):
print('here we wait for incoming messages ...')

# Create the tracer for processing incoming messages.
tracer = sdk.trace_incoming_message_process(msi_handle)

# Now we can set the vendor message and correlation IDs. It's possible to set them
# either before the tracer is started or afterwards. But they have to be set before
# the tracer ends.
tracer.set_vendor_message_id('message_id')
with tracer:
print('handle incoming message')
tracer.set_correlation_id('correlation_id')

def mock_outgoing_message():
sdk = getsdk()

# Create the messaging system info object.
msi_handle = sdk.create_messaging_system_info(
'MyPythonReceiverVendor', 'MyPythonDestination', MessagingDestinationType.TOPIC,
onesdk.Channel(onesdk.ChannelType.TCP_IP, '10.11.12.13:1415'))

with msi_handle:
# Create the outgoing message tracer;
with sdk.trace_outgoing_message(msi_handle) as tracer:
# Set the message and correlation IDs.
tracer.set_vendor_message_id('msgId')
tracer.set_correlation_id('corrId')

print('handle outgoing message')

def mock_custom_service():
sdk = getsdk()

with sdk.trace_custom_service('my_fancy_transaction', 'MyFancyService'):
print('do some fancy stuff')

def _diag_callback(text):
print(text)

Expand Down Expand Up @@ -237,6 +290,10 @@ def main():

mock_outgoing_web_request()

mock_outgoing_message()

mock_custom_service()

# We use trace_incoming_remote_call here, because it is one of the few
# calls that create a new path if none is running yet.
with sdk.trace_incoming_remote_call('main', 'main', 'main'):
Expand Down
2 changes: 1 addition & 1 deletion src/oneagent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

# See https://www.python.org/dev/peps/pep-0440/ "Version Identification and
# Dependency Specification"
__version__ = '1.1.0'
__version__ = '1.2.0'

logger = logging.getLogger('py_sdk')
logger.setLevel(logging.CRITICAL + 1) # Disabled by default
Expand Down
68 changes: 68 additions & 0 deletions src/oneagent/_impl/native/sdkctypesiface.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,74 @@ def __init__(self, libname):
None,
public=False), CCString)

self._init_messaging()

self._init_custom_service()


def _init_custom_service(self):
initfn = self._initfn

initfn(
'customservicetracer_create_p',
(CCStringPInArg, CCStringPInArg),
handle_t).__doc__ = \
'(service_method, service_name) -> tracer'


def _init_messaging(self):
initfn = self._initfn

initfn(
'messagingsysteminfo_create_p',
(CCStringPInArg, CCStringPInArg, ctypes.c_int32, ctypes.c_int32, CCStringPInArg),
handle_t).__doc__ = \
'(vendor_name, destination_name, destination_type, \
channel_type, channel_endpoint) -> tracer'

initfn(
'messagingsysteminfo_delete',
(handle_t,),
None)

initfn(
'outgoingmessagetracer_create',
(handle_t,),
handle_t)

initfn(
'outgoingmessagetracer_set_vendor_message_id_p',
(handle_t, CCStringPInArg),
None).__doc__ = \
'(tracer_handle, vendor_message_id)'

initfn(
'outgoingmessagetracer_set_correlation_id_p',
(handle_t, CCStringPInArg),
None).__doc__ = '(tracer_handle, correlation_id)'

initfn(
'incomingmessagereceivetracer_create',
(handle_t,),
handle_t)

initfn(
'incomingmessageprocesstracer_create',
(handle_t,),
handle_t)

initfn(
'incomingmessageprocesstracer_set_vendor_message_id_p',
(handle_t, CCStringPInArg),
None).__doc__ = \
'(tracer_handle, vendor_message_id)'

initfn(
'incomingmessageprocesstracer_set_correlation_id_p',
(handle_t, CCStringPInArg),
None).__doc__ = '(tracer_handle, correlation_id)'


def initialize(self):
result = self._initialize()

Expand Down
39 changes: 37 additions & 2 deletions src/oneagent/_impl/native/sdknulliface.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,45 @@ def customrequestattribute_add_strings(self, keys, values, count):
def customrequestattribute_add_string(self, key, value):
pass

#pylint:enable=invalid-name

def trace_in_process_link(self, link_bytes):
pass

def create_in_process_link(self):
pass

# Messaging API

#pylint:disable=too-many-arguments
def messagingsysteminfo_create(self, vendor_name, destination_name, destination_type,
channel_type, channel_endpoint):
return NULL_HANDLE

def messagingsysteminfo_delete(self, handle):
pass

def outgoingmessagetracer_create(self, handle):
return NULL_HANDLE

def outgoingmessagetracer_set_vendor_message_id(self, handle, vendor_message_id):
pass

def outgoingmessagetracer_set_correlation_id(self, handle, correlation_id):
pass

def incomingmessagereceivetracer_create(self, handle):
return NULL_HANDLE

def incomingmessageprocesstracer_create(self, handle):
return NULL_HANDLE

def incomingmessageprocesstracer_set_vendor_message_id(self, handle, message_id):
pass

def incomingmessageprocesstracer_set_correlation_id(self, handle, correlation_id):
pass

#pylint:enable=too-many-arguments
#pylint:enable=invalid-name

def customservicetracer_create(self, service_method, service_name):
return NULL_HANDLE
Loading

0 comments on commit 36427c3

Please sign in to comment.