Native ADK

The Native ADK provides both tagging and instrumentation on the source-code level. It can be used for all supported platforms and for all applications that can load and call a C or C++ library.

The Native ADK provides a set of C and C++ macros to be used for instrumenting the source code. These macros provide the following:

  • Initialization: Set configuration values. Connect to an AppMon Server (that is, to a stand-alone or Server-integrated Collector).
  • Sensor Placement: Define entry and exit points. Capture arguments and return values.
  • Tagging: Trace PurePaths.

Initialization

Macro Description
DYNATRACE_SET("<key>=<value>"); Use this macro to define configuration parameters directly in your code. Use either environment variables or command-line arguments as described below.
The <key> can be any known configuration parameter (see Configuration below), but the dt_ prefix needs to be omitted, for example DYNATRACE_SET("agentname=MySpecialAgent") for setting the DT_AGENTNAME.
int result = DYNATRACE_INITIALIZE(&argc, &argv); This macro initializes the Agent. ADK-specific arguments (arguments starting with --dt) are removed from argc and argv. Any calls except DYNATRACE_SET before this initialization step are ignored. It's good practice to put this macro directly in the main() method, because it should be called only once per application. The return value (result) is 0 if the ADK is initialized successfully or was already initialized in a previous call; -1 if any error occurred (for example if the Agent library failed to load).
DYNATRACE_REINITIALIZE(); This call is needed by the child process after a fork(), because the Agent was left in a defunct state.
DYNATRACE_UNINITIALIZE(); This macro terminates and shuts down the Agent connection, and releases any resources. Any calls after this step are ignored. It's good practice to put this macro at the end of the main() method, because it should be called only once when the application terminates.

Sensor placement and argument capturing

Two alternative macro sets are available, one for pure C code and one for C++. The C macros can also be used in C++ environments. They are fully compatible in case the code base to be instrumented consists of both C and C++ applications.

Both macro sets are described in the table.

C and C++ Macros

C Macros C++ Macros
DYNATRACE_API("<API>");

Defines the API for a Sensor. This macro must be placed before entering a Sensor.
DYNATRACE_API("<API>");

Same macro as in C.
DYNATRACE_START_PUREPATH();
DYNATRACE_EXIT();

Places a Sensor and marks it as an entry point to start a PurePath.
Requires the DYNATRACE_EXIT macro for marking the end point of the Sensor.
DYNATRACE_AUTO_PUREPATH();

Places a Sensor and marks it as an entry point.
Does not require an exit macro.
DYNATRACE_ENTER();
DYNATRACE_EXIT();

Places a Sensor without starting a PurePath.
Requires DYNATRACE_EXIT for marking the end point of the Sensor.
DYNATRACE_AUTO_NODE();

Places a Sensor in C++.
Does not require an exit macro.
DYNATRACE_ENTER_CAPTURE(
DYNATRACE_CAPTURE_<type> (<arg1>)
DYNATRACE_CAPTURE_<type> (<arg2>)
...
);
...
DYNATRACE_EXIT();

Argument capturing:
DYNATRACE_ENTER_CAPTURE places a Sensor to enable argument capturing.
Individual macros are available the various argument types:
  • DYNATRACE_CAPTURE_BOOL(arg)
  • DYNATRACE_CAPTURE_CHAR(arg)
  • DYNATRACE_CAPTURE_INT16(arg)
  • DYNATRACE_CAPTURE_INT32(arg)
  • DYNATRACE_CAPTURE_INT64(arg)
  • DYNATRACE_CAPTURE_FLOAT(arg)
  • DYNATRACE_CAPTURE_DOUBLE(arg)
  • DYNATRACE_CAPTURE_STRING(arg)
DYNATRACE_AUTO_NODE_CAPTURE(
DYNATRACE_CAPTURE << arg1 << arg2 << arg *n*
);

Argument capturing in C++:
DYNATRACE_AUTO_NODE_CAPTURE places a Sensor to enable argument capturing.
DYNATRACE_CAPTURE creates a capture instance that you can stream arguments onto.
For compilers that do not support variadic macros, macros are available that have a fixed number of arguments. For example:
DYNATRACE_ENTER_CAPTURE_1(arg1)
DYNATRACE_ENTER_CAPTURE_2(arg1, arg2)

For further details, refer to the documentation for the ADK.
Return value capturing:
DYNATRACE_EXIT_RETURN_<type> (<retval>)

The DYNATRACE_EXIT_RETURN_ <type> macros mark the end of a Sensor and capture the return value of the type as defined by the macro. The following return value types are supported:
  • DYNATRACE_EXIT_RETURN_BOOL(<retval>)
  • DYNATRACE_EXIT_RETURN_CHAR(<retval>)
  • DYNATRACE_EXIT_RETURN_INT16(<retval>)
  • DYNATRACE_EXIT_RETURN_INT32(<retval>)
  • DYNATRACE_EXIT_RETURN_INT64(<retval>)
  • DYNATRACE_EXIT_RETURN_FLOAT(<retval>)
  • DYNATRACE_EXIT_RETURN_DOUBLE(<retval>)
  • DYNATRACE_EXIT_RETURN_STRING(<retval>)
Return value capturing (C++ macro):
DYNATRACE_RETURN_<type> (<retval>)

The DYNATRACE_RETURN_<type> macros capture the return value of the type as defined by the macro and return the captured value. The following return value types are supported:
  • DYNATRACE_RETURN_BOOL(<retval>)
  • DYNATRACE_RETURN_CHAR(<retval>)
  • DYNATRACE_RETURN_INT16(<retval>)
  • DYNATRACE_RETURN_INT32(<retval>)
  • DYNATRACE_RETURN_INT64(<retval>)
  • DYNATRACE_RETURN_FLOAT(<retval>)
  • DYNATRACE_RETURN_DOUBLE(<retval>)
  • DYNATRACE_RETURN_STRING(<retval>)

All standard C/C++ data types and strings such as char* can be captured. Pointers as well as some Microsoft type definitions (such as LDPWORD) require casting. For example:

LPTSTR pchRequest;
LPDWORD pchBytes;
...
// C++ style argument capturing:
DYNATRACE_AUTO_NODE_CAPTURE(DYNATRACE_CAPTURE << (const char*)pchRequest << (int)\*pchBytes);

// C-style argument capturing:
DYNATRACE_ENTER_CAPTURE(
    DYNATRACE_CAPTURE_STRING(pchRequest),
    DYNATRACE_CAPTURE_INT32((int)\*pchBytes)
);

Tagging

Tagging in general closes the PurePath gap between distributed components that use proprietary remoting protocols. It enables continuing a client-side execution path on the server side.

To link a client path to a server path:

  1. On the client side, get the tag of the current PurePath and insert a link.
  2. Transfer the tag to the server.
  3. Start the server-side path, using the tag received from the client. This links the server's PurePath to the PurePath started on the client side.

The AppMon ADK provides support for steps 1 and 3. Transferring the tag from client to server depends on the protocol in use, which is probably proprietary. The transfer procedure is specific to the implementation.

Client-side and Server-side Tags

Client Side Server Side
DYNATRACE_GET_TAG(bytebuf, size);
DYNATRACE_GET_TAG_AS_STRING(strbuf, size);
Get the current AppMon tag either as a string (zero-terminated ASCII string) or as a byte array.

The size of the string buffer should be at least 100 characters. The size of the byte array is defined as 30 bytes. (This size is subject to change in future versions, but the length stays constant within an AppMon major version). To determine the exact binary tag length, use the ADK call DYNATRACE_GET_TAG_SIZE().
DYNATRACE_SET_TAG(bytebuf);
DYNATRACE_SET_TAG_FROM_STRING(strbuf);

These macros set the AppMon tag on the server side, either from a string or from a byte array.
DYNATRACE_LINK_CLIENT_PUREPATH(synchronous, bytebuf);
DYNATRACE_LINK_CLIENT_PUREPATH_BY_STRING(synchronous, strbuf);
Insert a synchronous (true) or asynchronous (false) link on the client side using the tag that was received by one of the DYNATRACE_GET_TAG macros previously described.

Synchronous/asynchronous pertains to the type of the PurePath link. Both link types do not result in a blocking call.
DYNATRACE_START_SERVER_PUREPATH();
Starts a server-side PurePath to continue the client-side PurePath.
DYNATRACE_END_SERVER_PUREPATH();
Terminates a server-side PurePath.
DYNATRACE_GET_TAG_SIZE();
Returns the amount of space required for the (binary) AppMon tag, in bytes.

GET_TAG must be called each time before issuing a remote call to the server side, even if it is still in the same transaction to the same server. The tag that is retrieved by GET_TAG identifies just one call, and it cannot be reused. This is also the case when using custom tags. Any request or message ID that is used to identify the remote call must be unique. Another call requires a new, unique identifier.

Important

Make sure DYNATRACE_LINK_CLIENT_PUREPATH() is invoked before DYNATRACE_START_SERVER_PUREPATH() . It is good practice to place the macro before sending a message to the server or before calling the server-side.

Helper macros

DYNATRACE_TAG_TO_STRING(tag, strbuf, strbuf_size);
DYNATRACE_STRING_TO_TAG(strbuf, tag, tag_size);

These macros can be used to convert the tag byte array into its string representation, and vice versa.

Tagging in context

The following diagram shows examples of the tagging macros.

Example Tagging Macros
Example Tagging Macros

Tag format

Tags are represented either as a 30-byte buffer or as a string. The string representation has the following format:

FW<tag-version>;<server id><agent id>;<tag id>;<hop count>;<entry agent id>;<entry tag id>;<path mode indicator>

Example: FW0;1;1481367847;0;4;1481367847;0;0

Logging

DYNATRACE_LOG(loglevel, message, logger_name);
This function inserts a custom log message, which shows as log node on the related PurePath and in the Logging dashlet.

Parameters

loglevel Numeric value for the log level.
message Log message text.
logger_name Name of the logger.

Configuration

You can configure instrumented C/C++ applications by using either environment variables or AppMon-specific command-line parameters.

Configuration Environment Variables and Parameters

ENVIRONMENT VARIABLE
Parameter
Default Value Comment
DT_AGENTLIBRARY
--dt_agentlibrary
- Path to the dynamic Agent library (including the Agent library's filename). The parameter is required.
DT_AGENTNAME
--dt_agentname
<appname> Agent name.
DT_SERVER
--dt_server
localhost:9998 Server (embedded Collector) host/port to connect to.
DT_AGENTACTIVE
--dt_agentactive
true Set Agent as active (true) or inactive (false).
DT_DEBUGADK or DT_DEBUG
--dt_debugadk or DT_DEBUG
false Enable (true) or disable (false) ADK debug information.
DT_HIRESTIMER
--dt_hirestimer
<not set> Specify the high-resolution timer that should be used. The timer type can be one of the following:
  • auto ‐ Select the timer automatically,
  • runtime ‐ Standard low-resolution clock,
  • cpu ‐ RDTSC or other CPU-based high-resolution clock (preferred).
  • os ‐ Windows QueryPerformanceCounter, available as a high-resolution clock
DT_LOGFILE
--dt_logfile
../../log/dt_<appname>_<pid>.log Log file. The path is relative to the Agent library.
DT_LOGLEVELFILE
--dt_loglevelfile
INFO Define the file log level. Valid level is any of the following: [ finest | finer | fine | config | info | warning | severe | debug | none ]
DT_LOGLEVELCON
--dt_loglevelcon
INFO Define the log level for the console output. Valid values are the same as for DT_LOGLEVELFILE.
DT_LOGFILESIZE
--dt_logfilesize
10 * 1024 * 1024 Define the maximum log file size, used for log file rotation. The size cannot be smaller than 64 kb.
DT_TRANSFORMATIONSAMPLES
--dt_transformationsamples
30 Number of samples to take for determining slow transformation (classes). Usually this does not need to be changed for the ADK.
DT_TRANSFORMATIONMAXAVGWAIT
--dt_transformationmaxavgwait
10 The maximum average wait time, in milliseconds, for determining slow transformation. Usually this does not need to be changed for the ADK.
DT_WAIT
--dt_wait
20 The initial wait timeout: the maximum time, in seconds, to wait for a connection to an AppMon Collector. If the connection cannot be established within this timeframe, the application continues uninstrumented. Defaults to 20 seconds.

The AppMon Collector may be referred to as the Server, for example in the AppMon Client dialog boxes, because in earlier releases the Collector was integrated in the AppMon Server. You can still use the Server-embedded Collector to save memory when you test AppMon, but the standalone Collector is enforced in production scenarios.
DT_SOCKTIMEOUT
-
30 The Native Agent's socket timeout, in seconds, for sending and receiving data.
DT_DEBUGFLAGS
--dt_debugflags
Comma-separated list of Agent debug options.

For a 64-bit AppMon installation on a 64-bit Windows machine, the command lines for the default 32-bit build target helloworld.exe are:

set DT_AGENTHOME=C:\Program Files\dynaTrace\dynaTrace <major.minorVersion>\agent\lib helloworld.exe --dt_agentname=HelloWorld --dt_agentlibrary=%DT_AGENTHOME%\dtagent.dll --dt_debugadk=true

Supply the command-line parameter values as any combination of string literals or environment variables. If you prefer to test from the VS IDE, supply arguments in the project's Property Pages window.

helloworld.exe project properties
helloworld.exe project properties

Sample applications

Sample applications are available with the AppMon ADK to demonstrate its usage. They are installed the samples subdirectory:

  • HelloWorld C++: A C++ application that starts and stops transactions, captures arguments, and traces across thread boundaries.
  • Java and JNI: A sample application that demonstrations tagging Java calls to JNI functions.
  • MultiApp: A sample application implemented in C++, Java, and .NET that demonstrates tagging over sockets using different technologies. The application can be run as Client or Server. The Client sends a request to the Server to multiply two numbers.

To build the samples, add the Agent ADK library to the lib directory (Java) or to the reference build path (.NET). For detailed information. refer to the readme files for the applications.

Running helloworld

  1. Compile helloworld:
    Note: The revision digit is not part of the AppMon component installation path.
    • On Windows (with Microsoft Visual Studio):
      1. Open <ADK_base_dir>/samples/HelloWorld C++/helloworld.sln (where <ADK_base_dir> is the ADK directory, for example C:\Users\user_name\Documents\Visual Studio 2013\ADK60).
      2. Compile and link the solution. The default configuration is debug and the 32-bit platform.
    • On Linux/Unix (with GNU Make):
      1. Open a shell and switch to the HelloWorld sample directory: cd <ADK_base_dir>/samples/HelloWorld C++ (where <ADK_base_dir> is the ADK installation directory. For example, /home/user_name/dynatrace-7.0).
      2. Compile and link by issuing the make command in that directory. By default helloworld is built as 32-bit application.
  2. Configure the AppMon Server.
    1. Launch the AppMon Server and Collector, and connect the AppMon Client.
    2. Import <ADK_base_dir>/Samples/ADK.profile.xml:
      • AppMon 2017 May In the Cockpit right-click System Profiles and select Import System Profile.
      • AppMon 2018 February In the Session selector click Manage System Profiles. In the System Profiles dashlet, click Import System Profile.
    3. Review the profile's HelloWorld Agent Group > Agent Mappings for details.
  3. Run helloworld with tracing.
    1. Open a command-line window.
    2. Navigate to the directory where the helloworld executable is compiled, on Windows it's by default: C:\Users\user_name\Documents\Visual Studio 2013\ADK56\samples\HelloWorld C++\Debug\Win32 on Linux/Unix it's the previously listed directory: <ADK_base_dir>/samples/HelloWorld C++.
    3. Run helloworld with command-line parameters (same for all platforms) and environment variables set as described.
  4. Diagnose helloworld.
    1. Open the PurePath dashlet: System Profiles > ADK > Diagnose Performance > PurePaths. The dashlet shows the full trace including captured arguments, execution times, and CPU times.
    2. From the PurePath, you can open or drill down into all AppMon dashlets. For example, right-click on the PurePath and drill down to the Sequence Diagram. All AppMon features are available. You can define measures, incident rules, and Business Transactions to monitor response times of your libraries or SLAs for your services.