Skip to content

Commit 36427c3

Browse files
authored
Merge pull request #5 from Dynatrace/prepare-1.2.0
imported 1.2.0 changes
2 parents f7b121b + 9e005e3 commit 36427c3

File tree

13 files changed

+587
-8
lines changed

13 files changed

+587
-8
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ dist/
1010
/tmp/
1111
*.egg-info
1212
.pytest_cache/
13+
/.project
14+
/.pydevproject
15+
/.README.md.html
16+
/.settings

README.md

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ This SDK enables Dynatrace customers to extend request level visibility into Pyt
2020
* [Outgoing web requests](#outgoing-web-requests)
2121
* [Trace in-process asynchronous execution](#trace-in-process-asynchronous-execution)
2222
* [Custom request attributes](#custom-request-attributes)
23+
* [Custom services](#custom-services)
24+
* [Messaging](#messaging)
25+
* [Outgoing Messages](#outgoing-messaging)
26+
* [Incoming Messages](#incoming-messaging)
2327
- [Troubleshooting](#troubleshooting)
2428
* [Installation issues](#installation-issues)
2529
* [Post-installation issues](#post-installation-issues)
@@ -54,6 +58,7 @@ Dynatrace OneAgent version (it is the same as
5458
|:----------------------|:---------------------|:-----------------|
5559
|1.0 |1.1.0 |≥1.141 |
5660
|1.1 |1.3.1 |≥1.151 |
61+
|1.2 |1.4.1 |≥1.161 |
5762

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

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

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

413420

421+
<a name="custom-services"></a>
422+
### Custom services
423+
You can use the SDK to trace custom service methods. A custom service method is a meaningful part
424+
of your code that you want to trace but that does not fit any other tracer. An example could be
425+
the callback of a periodic timer.
426+
427+
```python
428+
with sdk.trace_custom_service('onTimer', 'CleanupTask'):
429+
# Do the cleanup task
430+
:
431+
```
432+
433+
Check out the documentation at:
434+
* [`trace_custom_service`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.SDK.trace_custom_service)
435+
436+
437+
<a name="messaging"></a>
438+
### Messaging
439+
440+
You can use the SDK to trace messages sent or received via a messaging system. When tracing messages,
441+
we distinguish between:
442+
443+
* sending a message
444+
* waiting for and receiving a message
445+
* processing a received message
446+
447+
<a name="outgoing-messaging"></a>
448+
#### Outgoing Messages
449+
450+
All messaging related tracers need a messaging system info object which you have to create prior
451+
to the respective messaging tracer, which is an outgoing message tracer in the example below.
452+
453+
```python
454+
msi_handle = sdk.create_messaging_system_info(
455+
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
456+
ChannelType.TCP_IP, '10.11.12.13')
457+
458+
with msi_handle:
459+
with sdk.trace_outgoing_message(msi_handle) as tracer:
460+
# Get and set the Dynatrace tag.
461+
tag = tracer.outgoing_dynatrace_string_tag
462+
message_to_send.add_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME, tag)
463+
464+
# Send the message.
465+
the_queue.send(message_to_send)
466+
467+
# Optionally set message and/or correlation IDs
468+
tracer.set_vendor_message_id(message_to_send.get_message_id())
469+
tracer.set_correlation_id(message_to_send.get_correlation_id())
470+
```
471+
472+
<a name="incoming-messaging"></a>
473+
#### Incoming Messages
474+
475+
On the incoming side, we need to differentiate between the blocking receiving part and processing
476+
the received message. Therefore two different tracers are being used:
477+
478+
* IncomingMessageReceiveTracer
479+
* IncomingMessageProcessTracer
480+
481+
```python
482+
msi_handle = sdk.create_messaging_system_info(
483+
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
484+
ChannelType.TCP_IP, '10.11.12.13')
485+
486+
with msi_handle:
487+
# Create the receive tracer for incoming messages.
488+
with sdk.trace_incoming_message_receive(msi_handle):
489+
# This is a blocking call, which will return as soon as a message is available.
490+
Message query_message = the_queue.receive()
491+
492+
# Get the Dynatrace tag from the message.
493+
tag = query_message.get_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME)
494+
495+
# Create the tracer for processing incoming messages.
496+
tracer = sdk.trace_incoming_message_process(msi_handle, str_tag=tag)
497+
tracer.set_vendor_message_id(query_message.get_vendor_id())
498+
tracer.set_correlation_id(query_message.get_correlation_id())
499+
500+
with tracer:
501+
# Now let's handle the message ...
502+
print('handle incoming message')
503+
```
504+
505+
In case of non-blocking receive (e. g. using an event handler), there is no need to use an
506+
IncomingMessageReceiveTracer - just trace processing of the message by using the IncomingMessageProcessTracer:
507+
508+
```python
509+
msi_handle = sdk.create_messaging_system_info(
510+
'myMessagingSystem', 'requestQueue', MessagingDestinationType.QUEUE,
511+
ChannelType.TCP_IP, '10.11.12.13')
512+
513+
def on_message_received(message):
514+
# Get the Dynatrace tag from the message.
515+
tag = message.get_header_field(oneagent.sdk.DYNATRACE_MESSAGE_PROPERTY_NAME)
516+
517+
# Create the tracer for processing incoming messages.
518+
tracer = sdk.trace_incoming_message_process(msi_handle, str_tag=tag)
519+
tracer.set_vendor_message_id(message.get_vendor_id())
520+
tracer.set_correlation_id(message.get_correlation_id())
521+
522+
with tracer:
523+
# Now let's handle the message ...
524+
print('handle incoming message')
525+
```
526+
527+
See the documentation for more information:
528+
529+
* [`create_messaging_system_info`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.SDK.create_messaging_system_info)
530+
* [`trace_outgoing_message`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_outgoing_message)
531+
* [`trace_incoming_message_receive`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_incoming_message_receive)
532+
* [`trace_incoming_message_process`](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/sdkref.html#oneagent.sdk.tracers.trace_incoming_message_process)
533+
* [General information on tagging](https://dynatrace.github.io/OneAgent-SDK-for-Python/docs/tagging.html)
534+
535+
414536
<a name="troubleshooting"></a>
415537
## Troubleshooting
416538

docs/tagging.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ The following classes are incoming-taggable:
2424
:meth:`oneagent.sdk.SDK.trace_incoming_remote_call`
2525
- :class:`IncomingWebRequestTracer` /
2626
:meth:`oneagent.sdk.SDK.trace_incoming_web_request`
27+
- :class:`IncomingMessageProcessTracer` /
28+
:meth:`oneagent.sdk.SDK.trace_incoming_message_process`
2729

2830
The following classes are :class:`OutgoingTaggable`:
2931

3032
- :class:`OutgoingRemoteCallTracer`
3133
- :class:`OutgoingWebRequestTracer`
34+
- :class:`OutgoingMessageTracer`
3235

3336
You first use either :attr:`OutgoingTaggable.outgoing_dynatrace_string_tag` or
3437
:attr:`OutgoingTaggable.outgoing_dynatrace_byte_tag` to retrieve a string or

samples/basic-sdk-sample/basic_sdk_sample.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import oneagent # SDK initialization functions
2525
import oneagent.sdk as onesdk # All other SDK functions.
2626

27+
from oneagent.common import MessagingDestinationType
28+
29+
2730
try: # Python 2 compatibility.
2831
input = raw_input #pylint:disable=redefined-builtin
2932
except NameError:
@@ -166,6 +169,9 @@ def mock_incoming_web_request():
166169
# This call will trigger the diagnostic callback.
167170
sdk.add_custom_request_attribute('another key', None)
168171

172+
# This call simulates incoming messages.
173+
mock_process_incoming_message()
174+
169175
def _process_my_outgoing_request(_tag):
170176
pass
171177

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

199+
def mock_process_incoming_message():
200+
sdk = getsdk()
201+
202+
# Create the messaging system info object.
203+
msi_handle = sdk.create_messaging_system_info(
204+
'MyPythonSenderVendor', 'MyPythonDestination', MessagingDestinationType.QUEUE,
205+
onesdk.Channel(onesdk.ChannelType.UNIX_DOMAIN_SOCKET, 'MyPythonChannelEndpoint'))
206+
207+
with msi_handle:
208+
# Create the receive tracer for incoming messages.
209+
with sdk.trace_incoming_message_receive(msi_handle):
210+
print('here we wait for incoming messages ...')
211+
212+
# Create the tracer for processing incoming messages.
213+
tracer = sdk.trace_incoming_message_process(msi_handle)
214+
215+
# Now we can set the vendor message and correlation IDs. It's possible to set them
216+
# either before the tracer is started or afterwards. But they have to be set before
217+
# the tracer ends.
218+
tracer.set_vendor_message_id('message_id')
219+
with tracer:
220+
print('handle incoming message')
221+
tracer.set_correlation_id('correlation_id')
222+
223+
def mock_outgoing_message():
224+
sdk = getsdk()
225+
226+
# Create the messaging system info object.
227+
msi_handle = sdk.create_messaging_system_info(
228+
'MyPythonReceiverVendor', 'MyPythonDestination', MessagingDestinationType.TOPIC,
229+
onesdk.Channel(onesdk.ChannelType.TCP_IP, '10.11.12.13:1415'))
230+
231+
with msi_handle:
232+
# Create the outgoing message tracer;
233+
with sdk.trace_outgoing_message(msi_handle) as tracer:
234+
# Set the message and correlation IDs.
235+
tracer.set_vendor_message_id('msgId')
236+
tracer.set_correlation_id('corrId')
237+
238+
print('handle outgoing message')
239+
240+
def mock_custom_service():
241+
sdk = getsdk()
242+
243+
with sdk.trace_custom_service('my_fancy_transaction', 'MyFancyService'):
244+
print('do some fancy stuff')
245+
193246
def _diag_callback(text):
194247
print(text)
195248

@@ -237,6 +290,10 @@ def main():
237290

238291
mock_outgoing_web_request()
239292

293+
mock_outgoing_message()
294+
295+
mock_custom_service()
296+
240297
# We use trace_incoming_remote_call here, because it is one of the few
241298
# calls that create a new path if none is running yet.
242299
with sdk.trace_incoming_remote_call('main', 'main', 'main'):

src/oneagent/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090

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

9595
logger = logging.getLogger('py_sdk')
9696
logger.setLevel(logging.CRITICAL + 1) # Disabled by default

src/oneagent/_impl/native/sdkctypesiface.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,74 @@ def __init__(self, libname):
481481
None,
482482
public=False), CCString)
483483

484+
self._init_messaging()
485+
486+
self._init_custom_service()
487+
488+
489+
def _init_custom_service(self):
490+
initfn = self._initfn
491+
492+
initfn(
493+
'customservicetracer_create_p',
494+
(CCStringPInArg, CCStringPInArg),
495+
handle_t).__doc__ = \
496+
'(service_method, service_name) -> tracer'
497+
498+
499+
def _init_messaging(self):
500+
initfn = self._initfn
501+
502+
initfn(
503+
'messagingsysteminfo_create_p',
504+
(CCStringPInArg, CCStringPInArg, ctypes.c_int32, ctypes.c_int32, CCStringPInArg),
505+
handle_t).__doc__ = \
506+
'(vendor_name, destination_name, destination_type, \
507+
channel_type, channel_endpoint) -> tracer'
508+
509+
initfn(
510+
'messagingsysteminfo_delete',
511+
(handle_t,),
512+
None)
513+
514+
initfn(
515+
'outgoingmessagetracer_create',
516+
(handle_t,),
517+
handle_t)
518+
519+
initfn(
520+
'outgoingmessagetracer_set_vendor_message_id_p',
521+
(handle_t, CCStringPInArg),
522+
None).__doc__ = \
523+
'(tracer_handle, vendor_message_id)'
524+
525+
initfn(
526+
'outgoingmessagetracer_set_correlation_id_p',
527+
(handle_t, CCStringPInArg),
528+
None).__doc__ = '(tracer_handle, correlation_id)'
529+
530+
initfn(
531+
'incomingmessagereceivetracer_create',
532+
(handle_t,),
533+
handle_t)
534+
535+
initfn(
536+
'incomingmessageprocesstracer_create',
537+
(handle_t,),
538+
handle_t)
539+
540+
initfn(
541+
'incomingmessageprocesstracer_set_vendor_message_id_p',
542+
(handle_t, CCStringPInArg),
543+
None).__doc__ = \
544+
'(tracer_handle, vendor_message_id)'
545+
546+
initfn(
547+
'incomingmessageprocesstracer_set_correlation_id_p',
548+
(handle_t, CCStringPInArg),
549+
None).__doc__ = '(tracer_handle, correlation_id)'
550+
551+
484552
def initialize(self):
485553
result = self._initialize()
486554

src/oneagent/_impl/native/sdknulliface.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,45 @@ def customrequestattribute_add_strings(self, keys, values, count):
228228
def customrequestattribute_add_string(self, key, value):
229229
pass
230230

231-
#pylint:enable=invalid-name
232-
233231
def trace_in_process_link(self, link_bytes):
234232
pass
235233

236234
def create_in_process_link(self):
237235
pass
236+
237+
# Messaging API
238+
239+
#pylint:disable=too-many-arguments
240+
def messagingsysteminfo_create(self, vendor_name, destination_name, destination_type,
241+
channel_type, channel_endpoint):
242+
return NULL_HANDLE
243+
244+
def messagingsysteminfo_delete(self, handle):
245+
pass
246+
247+
def outgoingmessagetracer_create(self, handle):
248+
return NULL_HANDLE
249+
250+
def outgoingmessagetracer_set_vendor_message_id(self, handle, vendor_message_id):
251+
pass
252+
253+
def outgoingmessagetracer_set_correlation_id(self, handle, correlation_id):
254+
pass
255+
256+
def incomingmessagereceivetracer_create(self, handle):
257+
return NULL_HANDLE
258+
259+
def incomingmessageprocesstracer_create(self, handle):
260+
return NULL_HANDLE
261+
262+
def incomingmessageprocesstracer_set_vendor_message_id(self, handle, message_id):
263+
pass
264+
265+
def incomingmessageprocesstracer_set_correlation_id(self, handle, correlation_id):
266+
pass
267+
268+
#pylint:enable=too-many-arguments
269+
#pylint:enable=invalid-name
270+
271+
def customservicetracer_create(self, service_method, service_name):
272+
return NULL_HANDLE

0 commit comments

Comments
 (0)