• Home
  • Extend Dynatrace
  • Extend user experience and behavior
  • Dynatrace OpenKit API methods

Dynatrace OpenKit API methods

Dynatrace OpenKit offers a number of API methods that enable you to integrate OpenKit into your application. The sections below describe how to use each of these OpenKit methods.

Obtain an OpenKit instance

To obtain a new OpenKit instance, use DynatraceOpenKitBuilder.

java
String applicationID = "application-id"; long deviceID = Util.getDeviceID(); String endpointURL = "https://tenantid.beaconurl.com/mbeacon"; OpenKit openKit = new DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID).build();
cs
string applicationID = "application-id"; long deviceID = Util.GetDeviceID(); string endpointURL = "https://tenantid.beaconurl.com/mbeacon"; IOpenKit openKit = new DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID).Build();
cpp
const char* applicationID = "application-id"; int64_t deviceID = Util::GetDeviceID(); const char* endpointURL = "https://tenantid.beaconurl.com/mbeacon"; std::shared_pointer<openkit::IOpenKit> openKit = openkit::DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID).build();
c
const char* applicationID = "application-id"; int64_t deviceID = GetDeviceID(); const char* endpointURL = "https://tenantid.beaconurl.com/mbeacon"; struct OpenKitConfigurationHandle* configurationHandle = createOpenKitConfiguration(endpointURL, applicationID, deviceID); struct OpenKitHandle* openKitHandle = createDynatraceOpenKit(configurationHandle); destroyOpenKitConfiguration(configurationHandle);
javascript
const applicationID: string = 'application-id'; const deviceID: number = Util.getDeviceID(); const endpointURL: string = 'https://tenantid.beaconurl.com/mbeacon'; const openkit = new OpenKitBuilder(endpointURL, applicationID, deviceID).build();
  • endpointURL is the Dynatrace endpoint that OpenKit communicates with. You can find the endpoint URL in your custom application settings. See Instrument your application using Dynatrace OpenKit for more information.
  • applicationID is the unique identifier of the application. You can find the application ID in your custom application settings. See Instrument your application using Dynatrace OpenKit for more information.
  • deviceID is a unique identifier, which can be used to uniquely identify a device.

In addition to the mandatory parameters described above, the builder provides additional methods to further customize OpenKit. These include device-specific information like the operating system, manufacturer, or model ID.

Method nameDescriptionDefault valueSince version
withApplicationVersionSets the application versionOpenKit version1.0.1
withOperatingSystemSets the operating system nameOpenKit <OpenKit version>1.0.1
withManufacturerSets the manufacturerDynatrace1.0.1
withModelIDSets the model IDOpenKitDevice1.0.1
withBeaconCacheMaxRecordAgeSets the maximum age of an entry in the beacon cache in milliseconds1 h 45 min1.0.1
withBeaconCacheLowerMemoryBoundarySets the lower memory boundary of the beacon cache in bytes80 MB1.0.1
withBeaconCacheUpperMemoryBoundarySets the upper memory boundary of the beacon cache in bytes100 MB1.0.1
withLoggerSets a custom Logger replacing the currently set oneDefaultLogger1.0.1
withTrustManagerSets a custom SSLTrustManager replacing the currently set oneSSLStrictTrustManager1.0.1
withDataCollectionLevelSets the data collection levelDataCollectionLevel.USER_BEHAVIOR1.1.0
withCrashReportingLevelSets the crash reporting levelCrashReportingLevel.OPT_IN_CRASHES1.1.0
withLogLevelSets the default log level when the built-in logger is usedLogLevel.WARN2.0.0
withHttpRequestInterceptorSets the Interceptor for requests to Dynatrace backendsNullHttpRequestInterceptor2.2.0
withHttpResponseInterceptorSets the Interceptor for responses received from Dynatrace backendsNullHttpResponseInterceptor2.2.0
Method nameDescriptionDefault valueSince version
WithApplicationVersionSets the application versionOpenKit version1.0.1
WithOperatingSystemSets the operating system nameOpenKit <OpenKit version>1.0.1
WithManufacturerSets the manufacturerDynatrace1.0.1
WithModelIDSets the model IDOpenKitDevice1.0.1
WithBeaconCacheMaxRecordAgeSets the maximum age of an entry in the beacon cache in milliseconds1 h 45 min1.0.1
WithBeaconCacheLowerMemoryBoundarySets the lower memory boundary of the beacon cache in bytes80 MB1.0.1
WithBeaconCacheUpperMemoryBoundarySets the upper memory boundary of the beacon cache in bytes100 MB1.0.1
WithLoggerSets a custom ILogger replacing the currently set oneDefaultLogger1.0.1
WithTrustManagerSets a custom ISSLTrustManager replacing the currently set oneSSLStrictTrustManager1.0.1
WithDataCollectionLevelSets the data collection levelDataCollectionLevel.USER_BEHAVIOR1.1.0
WithCrashReportingLevelSets the crash reporting levelCrashReportingLevel.OPT_IN_CRASHES1.1.0
WithLogLevelSets the default log level when the built-in logger is usedLogLevel.WARN2.0.0
WithHttpRequestInterceptorSets the Interceptor for requests to Dynatrace backendsNullHttpRequestInterceptor2.2.0
WithHttpResponseInterceptorSets the Interceptor for responses received from Dynatrace backendsNullHttpResponseInterceptor2.2.0
Method nameDescriptionDefault valueSince version
withApplicationVersionSets the application versionOpenKit version1.0.0
withOperatingSystemSets the operating system nameOpenKit <OpenKit version>1.0.0
withManufacturerSets the manufacturerDynatrace1.0.0
withModelIDSets the model IDOpenKitDevice1.0.0
withBeaconCacheMaxRecordAgeSets the maximum age of an entry in the beacon cache in milliseconds1 h 45 min1.0.0
withBeaconCacheLowerMemoryBoundarySets the lower memory boundary of the beacon cache in bytes80 MB1.0.0
withBeaconCacheUpperMemoryBoundarySets the upper memory boundary of the beacon cache in bytes100 MB1.0.0
withLoggerSets a custom ILogger replacing the currently set oneDefaultLogger1.0.0
withTrustManagerSets a custom ISSLTrustManager replacing the currently set oneSSLStrictTrustManager1.0.0
withDataCollectionLevelSets the data collection levelDataCollectionLevel::USER_BEHAVIOR1.0.0
withCrashReportingLevelSets the crash reporting levelCrashReportingLevel::OPT_IN_CRASHES1.0.0
withLogLevelSets the default log level when the built-in logger is usedLogLevel.WARN2.0.0
withHttpRequestInterceptorSets the Interceptor for requests to Dynatrace backendsNullHttpRequestInterceptor2.2.0
withHttpResponseInterceptorSets the Interceptor for responses received from Dynatrace backendsNullHttpResponseInterceptor2.2.0
Method nameDescriptionDefault valueSince version
useApplicationVersionForConfigurationSets the application versionOpenKit version1.0.0
useOperatingSystemForConfigurationSets the operating system nameOpenKit <OpenKit version>1.0.0
useManufacturerForConfigurationSets the manufacturerDynatrace1.0.0
useModelIDForConfigurationSets the model IDOpenKitDevice1.0.0
useBeaconCacheBehaviorForConfigurationSets caching behavior for the beacon cache1 h 45 min retention, 80 MB lower memory boundary, 100 MB upper memory boundary1.0.0
useLoggerForConfigurationSets a custom ILogger replacing the currently set oneA default logger, logging to stdout, is used as fallback1.0.0
useTrustModeForConfigurationSets a custom ISSLTrustManager replacing the currently set oneSTRICT_TRUST1.0.0
useDataCollectionLevelForConfigurationSets the data collection levelDATA_COLLECTION_LEVEL_USER_BEHAVIOR1.0.0
useCrashReportingLevelForConfigurationSets the crash reporting levelCRASH_REPORTING_LEVEL_OPT_IN_CRASHES1.0.0
useDefaultLogLevelForConfigurationSets the default log level when the built-in logger is usedLogLevel.WARN2.0.0
useHttpRequestInterceptorForConfigurationSets the Interceptor for requests to Dynatrace backendsNullHttpRequestInterceptor2.2.0
useHttpResponseInterceptorForConfigurationSets the Interceptor for responses received from Dynatrace backendsNullHttpResponseInterceptor2.2.0
Method nameDescriptionDefault valueSince version
withApplicationVersionSets the application versionOpenKit version1.0.0
withOperatingSystemSets the operating system nameOpenKit <OpenKit version>1.0.0
withManufacturerSets the manufacturerDynatrace1.0.0
withModelIDSets the model IDOpenKitDevice1.0.0
withUserLanguageSets the user language1.0.0
withScreenResolutionSets the screen resolution1.0.0
withScreenOrientationSets the screen orientation1.0.0
withCommunicationChannelSets the communication channelHttpCommunicationChannel1.0.0
withRandomNumberProviderSets the random number providerDefaultRandomNumberProvider1.0.0
withLoggerFactorySets the logger factoryConsoleLoggerFactory1.0.0
withDataCollectionLevelSets the data collection level2 (User Behavior)1.0.0
withCrashReportingLevelSets the crash reporting level2 (OptIn)1.0.0
withLogLevelSets the default log level when the built-in logger is usedLogLevel.Info1.0.0

SSL/TLS security

All OpenKit communication to the backend happens via HTTPS. By default, OpenKit expects valid server certificates. However, it is possible, if needed, to bypass certificate validation. You can configure a custom trust manager using the builder.

We do not recommend bypassing TLS/SSL server certificate validation, since this allows man-in-the-middle attacks.

java
class MyCustomTrustManager implements SSLTrustManager { // implement interface methods } SSLTrustManager trustManager = new MyCustomTrustManager() OpenKit openKit = new DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID) .withTrustManager(trustManager) .build();
cs
class MyCustomTrustManager : ISSLTrustManager { // implement interface methods } ISSLTrustManager trustManager = new MyCustomTrustManager() OpenKit openKit = new DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID) .WithTrustManager(trustManager) .Build();
cpp
class MyCustomTrustManager : public openkit::ISSLTrustManager { // implement interface methods }; std::shared_ptr<openkit::ISSLTrustManager> trustManager = std::make_shared<MyCustomTrustManager>() OpenKit openKit = new DynatraceOpenKitBuilder(endpointURL, applicationID, deviceID) .withTrustManager(trustManager) .build();
c
void applySslOptions(CURL* curl) { // set CURL options accordingly } struct TrustManagerHandle* trustManager = createCustomTrustManager(&applySslOptions); // create OpenKit configuration and assign custom trust manager struct OpenKitConfigurationHandle* configurationHandle = createOpenKitConfiguration(endpointURL, applicationID, deviceID); useTrustModeForConfiguration(configurationHandle, CUSTOM_TRUST, trustManager); // create OpenKit instance struct OpenKitHandle* openKitHandle = createDynatraceOpenKit(configurationHandle);
javascript
class MyCustomTrustCommunicationChannel implements CommunicationChannel { // implement interface methods } const trustCommunicationChannel = new MyCustomTrustCommunicationChannel(); const openkit = new OpenKitBuilder(endpointURL, applicationID, deviceID) .withCommunicationChannel(trustCommunicationChannel) .build();

Enable verbose logging

By default, OpenKit uses a logger implementation that logs to stdout. If the default logger is used, you can enable verbose logging via DynatraceOpenKitBuilder. When the verbose mode is enabled, info and debug messages are logged.

You can also configure a custom logger. For details, see Dynatrace OpenKit logging.

Initialize OpenKit

When obtaining an OpenKit instance from the builder, the instance starts an automatic initialization phase. By default, initialization is performed asynchronously.

There might be situations when you need to ensure that initialization is completed before proceeding with the program logic, for example, in case of short-lived applications where a valid init and shutdown cannot be guaranteed. For such applications, OpenKit allows to wait for the initialization in two ways:

  • With timeout: The calling threads waits a given amount of time for OpenKit to initialize. The method returns false in case the timeout expired or a shutdown was performed in the meantime and true to indicate successful initialization.
  • Without timeout: The calling thread blocks until OpenKit is initialized. In case of misconfiguration this might block the calling thread indefinitely. The return value indicates whether the OpenKit instance has been initialized or a shutdown was performed meanwhile.
java
// wait until the OpenKit instance is fully initialized boolean success = openKit.waitForInitCompletion(); // wait up to 10 seconds for OpenKit to complete initialization long timeoutInMilliseconds = 10 * 1000; boolean success = openKit.waitForInitCompletion(timeoutInMilliseconds);
cs
// wait until the OpenKit instance is fully initialized bool success = openKit.WaitForInitCompletion(); // wait up to 10 seconds for OpenKit to complete initialization int timeoutInMilliseconds = 10 * 1000; bool success = openKit.WaitForInitCompletion(timeoutInMilliseconds);
cpp
// wait until the OpenKit instance is fully initialized bool success = openKit->waitForInitCompletion(); // wait up to 10 seconds for OpenKit to complete initialization int64_t timeoutInMilliseconds = 10 * 1000; bool success = openKit->waitForInitCompletion(timeoutInMilliseconds);
c
// wait until the OpenKit instance is fully initialized bool success = waitForInitCompletion(openKit); // wait up to 10 seconds for OpenKit to complete initialization int64_t timeoutInMilliseconds = 10 * 1000; bool success = waitForInitCompletionWithTimeout(openKit, timeoutInMilliseconds);
javascript
// wait until the OpenKit instance is fully initialized openKit.waitForInit((initializedSuccessfully) => {}); // wait up to 10 seconds for OpenKit to complete initialization const timeoutInMilliseconds = 10 * 1000; openKit.waitForInit(() => {}, timeoutInMilliseconds);

In addition, OpenKit enables you to verify whether or not it's been initialized.

java
boolean isInitialized = openKit.isInitialized(); if (isInitialized) { System.out.println("OpenKit is initialized"); } else { System.out.println("OpenKit is not yet initialized"); }
cs
bool isInitialized = openKit.IsInitialized; if (isInitialized) { Console.WriteLine("OpenKit is initialized"); } else { Console.WriteLine("OpenKit is not yet initialized"); }
cpp
bool isInitialized = openKit->isInitialized(); if (isInitialized) { std::cout << "OpenKit is initialized" << std::endl; } else { std::cout << "OpenKit is not yet initialized" << std::endl; }
c
bool isInitialized = isInitialized(openKit); if (isInitialized) { printf("OpenKit is initialized\n"); } else { printf("OpenKit is not yet initialized\n"); }
javascript
const isInitialized = openKit.isInitialized(); if (isInitialized) { console.log('OpenKit is initialized'); } else { console.log('OpenKit is not yet initialized'); }

Create a session

You can create a new session using the OpenKit instance obtained from the builder. When creating a new session, you can also provide an IP address.

  • If a valid IPv4 or IPv6 address is provided, it is assigned to the session.
  • If no IP address or an invalid IP address is provided, the IP address of the session is auto-detected and assigned on the server side.
java
// create a session and pass an IP address String clientIPAddress = "12.34.56.78"; Session sessionWithArgument = openKit.createSession(clientIPAddress); // create a session and let the IP be assigned on the server side // this overloaded method is available since OpenKit Java 1.4.0 Session sessionWithoutArgument = openKit.createSession();
cs
// create a session and pass an IP address string clientIPAddress = "12.34.56.78"; ISession sessionWithArgument = openKit.CreateSession(clientIPAddress); // create a session and let the IP be assigned on the server side // this overloaded method is available since OpenKit .NET 1.4.0 ISession sessionWithoutArgument = openKit.CreateSession();
cs
// create a session and pass an IP address const char* clientIPAddress = "12.34.56.78"; std::shared_ptr<openkit::ISession> sessionWithArgument = openKit->createSession(clientIPAddress); // create a session and let the IP be assigned on the server side // this overloaded method is available since OpenKit Native 1.1.0 std::shared_ptr<openkit::ISession> sessionWithoutArgument = openKit->createSession();
cs
// create a session and pass an IP address const char* clientIPAddress = "12.34.56.78"; SessionHandle* sessionWithArgument = createSession(openKit, clientIPAddress); // create a session and let the IP be assigned on the server side // this function is available since OpenKit Native 1.1.0 SessionHandle* sessionWithoutArgument = createSessionWithAutoIpDetermination(openKit);
javascript
// create a session and pass an IP address const clientIPAddress = "12.34.56.78"; const sessionWithArgument = openKit.createSession(clientIpAddress); // create a session and let the IP be assigned on the server side const sessionWithoutArgument = openKit.createSession();

Tag a user

You can tag the user assigned to a session. This enables you to search and filter specific user sessions and analyze individual user behavior over time in the backend.

java
session.identifyUser("jane.doe@example.com");
cs
session.IdentifyUser("jane.doe@example.com");
cpp
session->identifyUser("jane.doe@example.com");
c
identifyUser(session, "jane.doe@example.com");
javascript
session.identifyUser("jane.doe@example.com");

Finish a session

When a session is no longer needed, you should end it explicitly. Although all open sessions are automatically ended when OpenKit is shut down, it's highly recommended to manually end sessions that are no longer in use.

java
session.end(); session = null; // not needed, just used to indicate that the session is no longer valid.
cs
session.End(); session = null; // not needed, just used to indicate that the session is no longer valid.
cpp
session->end(); session = nullptr; // not needed, just used to indicate that the session is no longer valid.
c
endSession(session); session = NULL; // good pratice, as the allocated memory is freed in endSession
javascript
session.end();

Report a crash

You can report unexpected application crashes on a session.

java
private static int div(int numerator, int denominator) { return numerator / denominator; } public static void divWithCrash() { int numerator = 5; int denominator = 0; try { System.out.println("Got: " + div(numerator, denominator)); } catch (Exception e) { String errorName = e.getClass().getName(); String reason = e.getMessage(); String stackTrace = getStackTraceAsString(e); // get the stacktrace as string, similar as e.printStackTrace() // and now report the application crash via the session session.reportCrash(errorName, reason, stackTrace); } }
cs
private static int Div(int numerator, int denominator) { return numerator / denominator; } public static void DivWithCrash() { int numerator = 5; int denominator = 0; try { Console.WriteLine("Got: " + Div(numerator, denominator)); } catch (Exception e) { string errorName = e.GetType().ToString(); string reason = e.Message; string stackTrace = e.StackTrace; // and now report the application crash via the session session.ReportCrash(errorName, reason, stackTrace); } }
cpp
static int32_t div(int32_t numerator, int32_t denominator) { if (denominator == 0) { throw std::logic_error("Division by zero"); } return numerator / denominator; } static void divWithCrash() { int32_t numerator = 5; int32_t denominator = 0; try { int32_t result = div(numerator, denominator); std::cout << "Got: " << result << std::endl; } catch (std::logic_error& e) { const char* errorName = "std::logic_error"; // if RTTI is enabled, typeid could be used const char* reason = e.what(); const char* stackTrace = nullptr; // use a valid const char* if a stack trace can be generated // and now report the application crash via the session session->reportCrash(errorName, reason, stackTrace); } }
c
const char* errorName = "application crash"; const char* reason = "some reason indicator"; const char* stackTrace = NULL; // use a valid const char* if a stack trace can be generated // and now report the application crash via the session reportCrash(session, errorName, reason, stackTrace);
javascript
const error = new Error('Some error'); // and now report the application crash via the session session.reportCrash(e.name, e.message, e.stack);

Create custom and child actions

You can define and report custom actions. After you create a custom action, you can add a child action to it or enhance an action with additional information before finally closing it.

You should create custom actions from a session and child actions from a custom action.

java
String rootActionName = "rootActionName"; String childActionName = "childActionName"; // create a custom action for a session RootAction rootAction = session.enterAction(rootActionName); // create a child action for the custom action Action childAction = rootAction.enterAction(childActionName);
cs
string rootActionName = "rootActionName"; string childActionName = "childActionName"; // create a custom action for a session IRootAction rootAction = session.EnterAction(rootActionName); // create a child action for the custom action IAction childAction = rootAction.EnterAction(childActionName);
cpp
const char* rootActionName = "rootActionName"; const char* childActionName = "childActionName"; // create a custom action for a session std::shared_ptr<openkit::IRootAction> rootAction = session->enterAction(rootActionName); // create a child action for the custom action std::shared_ptr<openkit::IAction> childAction = rootAction->enterAction(childActionName);
c
const char* rootActionName = "rootActionName"; const char* childActionName = "childActionName"; // create a custom action for a session RootActionHandle* rootAction = enterRootAction(session, rootActionName); // create a child action for the custom action ActionHandle* childAction = enterAction(rootAction, childActionName);
javascript
const rootActionName = "rootActionName"; const childActionName = "childActionName"; // create a custom action for a session const rootAction = session.enterAction(rootActionName); // create a child action for the custom action const childAction = rootAction.enterAction(childActionName);

The maximum duration of a user action in custom apps is 10 minutes. When a user action takes longer than this, such an action is discarded and not reported to Dynatrace.

End an action

To record accurate timing information for actions, you should leave actions once they're finished.

java
Action parentAction = action.leaveAction(); // returns the appropriate custom action Action parent = parentAction.leaveAction(); // will always return null
cs
IAction parentAction = action.LeaveAction(); // returns the appropriate custom action IAction parent = parentAction.LeaveAction(); // will always return null
cpp
std::shared_ptr<openkit::IRootAction> parentAction = action->leaveAction(); // returns the appropriate custom action parentAction->leaveAction(); // return type is void
c
leaveAction(action); // return type is void leaveRootAction(rootAction); // return type is void
javascript
const parentAction = action.leaveAction(); // returns the appropriate custom action const parent = parentAction.leaveAction(); // will always return null

Cancel an action

Canceling an action is similar to leaving an action, except that the action is discarded and is not sent to Dynatrace. Open child objects, like child actions and web request tracers, are discarded as well. Child objects that have been closed previously are sent to the backend and might be processed, depending on the event type.

java
Action parentAction = action.cancelAction(); // returns the appropriate custom action Action parent = parentAction.cancelAction(); // will always return null
cs
IAction parentAction = action.CancelAction(); // returns the appropriate custom action IAction parent = parentAction.CancelAction(); // will always return null
cpp
std::shared_ptr<openkit::IRootAction> parentAction = action->cancelAction(); // returns the appropriate custom action parentAction->cancelAction(); // return type is void
c
cancelAction(action); // return type is void cancelRootAction(rootAction); // return type is void

Report an event

You can report named events on actions.

If you want to report standalone events with lots of additional information, see Report a business event.

java
String eventName = "eventName"; action.reportEvent(eventName); // also report on the RootAction rootAction.reportEvent(eventName);
cs
string eventName = "eventName"; action.ReportEvent(eventName); // also report on the RootAction rootAction.ReportEvent(eventName);
cpp
const char* eventName = "eventName"; action->reportEvent(eventName); // also report on the RootAction rootAction->reportEvent(eventName);
c
const char* eventName = "eventName"; reportEventOnAction(action, eventName); // also report on the RootAction reportEventOnRootAction(rootAction, eventName);
javascript
const eventName = "eventName"; action.reportEvent(eventName); // also report on the RootAction rootAction.reportEvent(eventName);

Report key-value pairs

You can report key-value pairs for actions, as shown in the example below.

Overloaded methods exist for the following value types:

  • 32-bit integer
  • 64-bit integer
  • Double
  • String
java
// first report a 32-bit int value String keyIntType = "intType"; int valueInt = 42; action.reportValue(keyIntType, valueInt); // then let's report a 64-bit long value String keyLongType = "longType"; long valueLong = Long.MIN_VALUE; action.reportValue(keyLongType, valueLong); // then let's report a double value String keyDoubleType = "doubleType"; double valueDouble = 3.141592653589793; action.reportValue(keyDoubleType, valueDouble); // and also a string value String keyStringType = "stringType"; String valueString = "The quick brown fox jumps over the lazy dog"; action.reportValue(keyStringType, valueString);
cs
// first report a 32-bit int value string keyIntType = "intType"; int valueInt = 42; action.ReportValue(keyIntType, valueInt); // then let's report a 64-bit long value string keyLongType = "longType"; long valueLong = long.MinValue; action.ReportValue(keyLongType, valueLong); // then let's report a double value string keyDoubleType = "doubleType"; double valueDouble = 3.141592653589793; action.ReportValue(keyDoubleType, valueDouble); // and also a string value string keyStringType = "stringType"; string valueString = "The quick brown fox jumps over the lazy dog"; action.ReportValue(keyStringType, valueString);
cpp
// first report a 32-bit integer value const char* keyIntType = "intType"; int32_t valueInt = 42; action->reportValue(keyIntType, valueInt); // then let's report a 64-bit integer value const char* keyLongType = "longType"; int64_t valueLong = LLONG_MIN; action->reportValue(keyLongType, valueLong); // then let's report a double value const char* keyDoubleType = "doubleType"; double valueDouble = 3.141592653589793; action->reportValue(keyDoubleType, valueDouble); // and also a string value const char* keyStringType = "stringType"; const char* valueString = "The quick brown fox jumps over the lazy dog"; action->reportValue(keyStringType, valueString);
c
// first report a 32-bit integer value const char* keyIntType = "intType"; int32_t valueInt = 42; reportIntValueOnAction(action, keyIntType, valueInt); // then let's report a 64-bit integer value const char* keyLongType = "longType"; int64_t valueLong = LLONG_MIN; reportInt64ValueOnAction(keyLongType, valueLong); // then let's report a double value const char* keyDoubleType = "doubleType"; double valueDouble = 3.141592653589793; reportDoubleValueOnAction(action, keyDoubleType, valueDouble); // and also a string value const char* keyStringType = "stringType"; const char* valueString = "The quick brown fox jumps over the lazy dog"; reportStringValueOnAction(action, keyStringType, valueString);
javascript
// first report a numeric value const keyNumberName = 'My reported numeric value'; const numericValue = 42; action.reportValue(keyNumberName, numericValue); // and also a string value const keyStringName = 'My reported string value'; const stringValue = 'The quick brown fox jumps over the lazy dog'; action.reportValue(keyStringName, stringValue);

Report an error

You can report an error including its name (errorName) and error code (errorCode).

java
String errorName = "Unknown Error"; int errorCode = 42; action.reportError(errorName, errorCode);
cs
string errorName = "Unknown Error"; int errorCode = 42; action.ReportError(errorName, errorCode);
cpp
const char* errorName = "Unknown Error"; int32_t errorCode = 42; action->reportError(errorName, errorCode);
c
const char* errorName = "Unknown Error"; int32_t errorCode = 42; // report error on a child action reportErrorOnAction(action, errorName, errorCode); // report error on a custom action reportErrorOnRootAction(rootAction, errorName, errorCode);
javascript
const errorName = 'Unknown error'; const errorCode = 42; action.reportError(errorName, errorCode);

You can also report the following additional information on the error:

  • required errorName—The human-readable name of the error.
  • optional causeName—The cause leading to the reported error, for example, the exception's class name.
  • optional causeDescription—The description of the cause leading to the error, for example, the exception's description.
  • optional stackTrace or causeStackTrace—The stack trace of the cause leading to the error.

The code snippet below shows how to report errors with additional information.

java
public void restrictedMethod() { if (!isUserAuthorized()) { // user is not authorized - report this as an error String errorName = "Authorization error"; String causeName = "User not authorized"; String causeDescription = "The current user is not authorized to call restrictedMethod."; String stackTrace = null; // no stack trace is reported action.reportError(errorName, causeName, causeDescription, stackTrace); return; } // ... further processing ... }
cs
public void RestrictedMethod() { if (!IsUserAuthorized()) { // user is not authorized - report this as an error string errorName = "Authorization error"; string causeName = "User not authorized"; string causeDescription = "The current user is not authorized to call restrictedMethod."; string stackTrace = null; // no stack trace is reported action.ReportError(errorName, causeName, causeDescription, stackTrace); return; } // ... further processing ... }
cpp
void RestrictedClass::restrictedMethod() { if (!isUserAuthorized()) { const char* errorName = "Authorization error"; const char* causeName = "User not authorized"; const char* causeDescription = "The current user is not authorized to call restrictedMethod."; const char* causeStackTrace = nullptr; // no stack trace is reported // report the error on IAction action->reportError(errorName, causeName, causeDescription, causeStackTrace); // report the error on IRootAction rootAction->reportError(errorName, causeName, causeDescription, causeStackTrace); return; } // ... further processing }
c
void restrictedFunction() { if (!isUserAuthorized()) { const char* errorName = "Authorization error"; const char* causeName = "User not authorized"; const char* causeDescription = "The current user is not authorized to call restrictedFunction."; const char* causeStackTrace = NULL; // no stack trace is reported // report error on child action reportErrorCauseOnAction(action, errorName, causeName, causeDescription, causeStackTrace); // report error on custom action reportErrorCauseOnRootAction(rootAction, errorName, causeName, causeDescription, causeStackTrace); return; } // ... further processing }

OpenKit Java and OpenKit .NET offer a convenience API to directly report caught exceptions, as demonstrated in the example below.

java
try { // call a method that is throwing an exception callMethodThrowingException(); } catch(Exception caughtException) { // report the caught exception as error via OpenKit String errorName = "Unknown Error"; action.reportError(errorName, caughtException); }
cs
try { // call a method that is throwing an exception CallMethodThrowingException(); } catch(Exception caughtException) { // report the caught exception as error via OpenKit string errorName = "Unknown Error"; action.ReportError(errorName, caughtException); }

Report a business event

Dynatrace SaaS version 1.253+

With sendBizEvent, you can report business events. These are standalone events, as Dynatrace sends them separately from user actions or user sessions.

For more information on business events, see Business Analytics in Dynatrace.

java
Map <String, JSONValue> attributes = new HashMap<String, JSONValue>(); attributes.put("event.name", JSONStringValue.fromString("Confirmed Booking")); attributes.put("screen", JSONStringValue.fromString("booking-confirmation")); attributes.put("product", JSONStringValue.fromString("Danube Anna Hotel")); attributes.put("amount", JSONNumberValue.fromDouble(358.35)); attributes.put("currency", JSONStringValue.fromString("USD")); attributes.put("reviewScore", JSONNumberValue.fromDouble(4.8)); attributes.put("arrivalDate", JSONStringValue.fromString("2022-11-05")); attributes.put("departureDate", JSONStringValue.fromString("2022-11-15")); attributes.put("journeyDuration", JSONNumberValue.fromLong(10)); attributes.put("adultTravelers", JSONNumberValue.fromLong(2)); attributes.put("childrenTravelers", JSONNumberValue.fromLong(0)); session.sendBizEvent('com.easytravel.funnel.booking-finished', attributes);
cs
Dictionary<string, JsonValue> attributes = new Dictionary<string, JsonValue>(); attributes.Add("event.name", JsonStringValue.FromString("Confirmed Booking")); attributes.Add("screen", JsonStringValue.FromString("booking-confirmation")); attributes.Add("product", JsonStringValue.FromString("Danube Anna Hotel")); attributes.Add("amount", JsonNumberValue.FromDouble(358.35)); attributes.Add("currency", JsonStringValue.FromString("USD")); attributes.Add("reviewScore", JsonNumberValue.FromDouble(4.8)); attributes.Add("arrivalDate", JsonStringValue.FromString("2022-11-05")); attributes.Add("departureDate", JsonStringValue.FromString("2022-11-15")); attributes.Add("journeyDuration", JsonNumberValue.FromLong(10)); attributes.Add("adultTravelers", JsonNumberValue.FromLong(2)); attributes.Add("childrenTravelers", JsonNumberValue.FromLong(0)); session.SendBizEvent("com.easytravel.funnel.booking-finished", attributes);
cpp
auto attributes = std::make_shared<openkit::json::JsonObjectValue::JsonObjectMap>( std::initializer_list<openkit::json::JsonObjectValue::JsonObjectMap::value_type>{ { "event.name", openkit::json::JsonStringValue::fromString("Confirmed Booking") }, { "screen", openkit::json::JsonStringValue::fromString("booking-confirmation") }, { "product", openkit::json::JsonStringValue::fromString("Danube Anna Hotel") }, { "amount", openkit::json::JsonNumberValue::fromDouble(358.35) }, { "currency", openkit::json::JsonStringValue::fromString("USD") }, { "reviewScore", openkit::json::JsonNumberValue::fromDouble(4.8) }, { "arrivalDate", openkit::json::JsonStringValue::fromString("2022-11-05") }, { "departureDate", openkit::json::JsonStringValue::fromString("2022-11-15") }, { "journeyDuration", openkit::json::JsonNumberValue::fromLong(10) }, { "adultTravelers", openkit::json::JsonNumberValue::fromLong(2) }, { "childrenTravelers", openkit::json::JsonNumberValue::fromLong(0) } } );
c
size_t attributesSize = 11; OpenKitPair* attributes = malloc(sizeof(OpenKitPair) * attributesSize); if (attributes == NULL) { fprintf(stderr, "malloc of attributes for sendBizEvent is not working."); exit(-1); } attributes[0] = (OpenKitPair) { "event.name", "\"Confirmed Booking\"" }; attributes[1] = (OpenKitPair) { "screen", "\"booking-confirmation\"" }; attributes[2] = (OpenKitPair) { "product", "\"Danube Anna Hotel\"" }; attributes[3] = (OpenKitPair) { "amount", "358.35" }; attributes[4] = (OpenKitPair) { "currency", "\"USD\"" }; attributes[5] = (OpenKitPair) { "reviewScore", "4.8" }; attributes[6] = (OpenKitPair) { "arrivalDate", "\"2022-11-05\"" }; attributes[7] = (OpenKitPair) { "departureDate", "\"2022-11-15\"" }; attributes[8] = (OpenKitPair) { "journeyDuration", "10" }; attributes[9] = (OpenKitPair) { "adultTravelers", "2" }; attributes[10] = (OpenKitPair) { "childrenTravelers", "0" }; sendBizEvent(sessionHandle, "Event", attributes, attributesSize); free(attributes);
javascript
session.sendBizEvent('com.easytravel.funnel.booking-finished', { 'event.name': 'Confirmed Booking', screen: 'booking-confirmation', product: 'Danube Anna Hotel', amount: 358.35, currency: 'USD', reviewScore: 4.8, arrivalDate: '2022-11-05', departureDate: '2022-11-15', journeyDuration: 10, adultTravelers: 2, childrenTravelers: 0, });

Trace web requests

One of the most powerful OpenKit features is web request tracing. When the application starts a web request, for example, HTTP GET, a special tag can be attached to the header. This header allows Dynatrace to correlate actions with a server-side distributed trace. An example is shown below.

java
// create URL and open URLConnection URL url = new URL("http://www.my-backend.com/api/v3/users"); URLConnection urlConnection = url.openConnection(); // create the WebRequestTracer WebRequestTracer webRequestTracer = action.traceWebRequest(urlConnection); webRequestTracer.start(); // consume data BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { // TODO - do something useful with response } in.close(); // stop web request tracing when done webRequestTracer.stop(200); // would use the HTTP response code normally. // -------------------------------------------- // alternative solution not using URLConnection // -------------------------------------------- String url = "http://www.my-backend.com/api/v3/users"; // create the WebRequestTracer WebRequestTracer webRequestTracer = action.traceWebRequest(url); // this is the HTTP header name & value which needs to be added to the HTTP request. String headerName = OpenKitConstants.WEBREQUEST_TAG_HEADER; String headerValue = webRequestTracer.getTag(); webRequestTracer.start(); // perform the request here & do not forget to add the HTTP header webRequestTracer.setBytesSent(12345); // 12345 bytes sent webRequestTracer.setBytesReceived(67890); // 67890 bytes received webRequestTracer.stop(200); // 200 was the response code
cs
string url = "http://www.my-backend.com/api/v3/users"; // create the WebRequestTracer IWebRequestTracer webRequestTracer = action.TraceWebRequest(url); // this is the HTTP header name & value which needs to be added to the HTTP request. string headerName = OpenKitConstants.WEBREQUEST_TAG_HEADER; string headerValue = webRequestTracer.Tag; // perform the request here & do not forget to add the HTTP header using (HttpClient httpClient = new HttpClient()) { // start timing webRequestTracer.Start(); // set the tag httpClient.DefaultRequestHeaders.Add(headerName, headerValue); // ... perform the request and process the response ... // set metadata webRequestTracer.SetBytesSent(12345); // 12345 bytes sent webRequestTracer.SetBytesReceived(67890); // 67890 bytes received webRequestTracer.Stop(200); // 200 was the response code }
cpp
const char* url = "http://www.my-backend.com/api/v3/users"; // create the WebRequestTracer std::shared_ptr<openkit::IWebRequestTracer> webRequestTracer = action->traceWebRequest(url); // this is the HTTP header name & value which needs to be added to the HTTP request. const char* headerName = openkit::WEBREQUEST_TAG_HEADER; const char* headerValue = webRequestTracer->getTag(); // start timing webRequestTracer->start(); // set the tag on httpRequest // Note: how to set this, depends on the HTTP client library in use httpRequest.addHeader(headerName, headerValue); // ... perform the request and process the response ... // set metadata webRequestTracer->setBytesSent(12345); // 12345 bytes sent webRequestTracer->setBytesReceived(67890); // 67890 bytes received webRequestTracer->stop(200); // 200 was the response code
c
const char* url = "http://www.my-backend.com/api/v3/users"; // create the WebRequestTracer on child action WebRequestTracerHandle* webRequestTracer = traceWebRequestOnRootAction(rootAction, url); // Alterantively web requests can be created on a child action like below // WebRequestTracerHandle* webRequestTracer = traceWebRequestOnAction(action, url); // this is the HTTP header name & value which needs to be added to the HTTP request. const char* headerName = WEBREQUEST_TAG_HEADER; const char* headerValue = getTag(webRequestTracer); // start timing startWebRequest(webRequestTracer) // set the tag on httpRequest // Note: how to set this, depends on the HTTP client library in use addCustomHeaderToWebRequest(httpRequest, headerName, headerValue); // ... perform the request and process the response ... // set metadata setBytesSent(webRequestTracer, 12345); // 12345 bytes sent setBytesReceived(webRequestTracer, 67890); // 67890 bytes received stopWebRequest(webRequestTracer, 200); // 200 was the response code // After calling stopWebRequest the allocated memory is freed and therefore // webRequestTracer is no longer valid. webRequestTracer = NULL;
javascript
const url = 'http://www.my-backend.com/api/v3/users'; // create the WebRequestTracer const webRequestTracer = action.traceWebRequest(url); const headerName = webRequestTagHeader; // webRequestTagHeader can be imported const headerValue = webRequestTracer.getTag(); webRequestTracer.start(); // perform the request here & do not forget to add the HTTP header webRequestTracer.setBytesSent(12345); webRequestTracer.setBytesReceived(67890); webRequestTracer.stop(200); // stop the web request tracer, with the response code

Terminate an OpenKit instance

When an OpenKit instance is no longer needed, for example, when the application using OpenKit is shut down, you can clear the obtained instance by invoking. A call to shutdown blocks the calling thread up to 10 seconds, while the OpenKit flushes data that hasn't been transmitted yet to the backend.

java
openKit.shutdown();
cs
openKit.Shutdown();
cpp
openKit->shutdown();
c
shutdownOpenKit(openKit);
javascript
openKit.shutdown();