From 4fa16323aa4b50bc7f49b971467fa7eef2afc429 Mon Sep 17 00:00:00 2001 From: Armin Ruech Date: Tue, 27 Nov 2018 16:07:06 +0100 Subject: [PATCH] v1.1.0-alpha SDK * add remote call tracer * add logging callback * update async tracer interface according to .NET guidelines Sample * add remote call samples * add combined samples * tidy up db samples * tidy up demo CLI Misc * update readme * add license headers * add package metadata for nupkg * cleanup --- .gitignore | 6 +- readme.md | 192 +++++-- .../Dynatrace.OneAgent.Sdk.Sample.sln | 56 +- .../CombinedSamples.cs | 79 +++ .../DatabaseRequestTracerSamples.cs | 538 +++++++++--------- .../Dynatrace.OneAgent.Sdk.Sample.csproj | 13 +- .../Dynatrace.OneAgent.Sdk.Sample/Program.cs | 69 --- .../RemoteCallTracerSamples.cs | 201 ++++++- .../SampleApplication.cs | 124 ++++ src/Api/Enums/ChannelType.cs | 26 +- src/Api/Enums/DatabaseVendor.cs | 106 ++-- src/Api/IDatabaseRequestTracer.cs | 40 +- src/Api/IIncomingRemoteCallTracer.cs | 26 +- src/Api/IIncomingTaggable.cs | 65 ++- src/Api/IIncomingWebRequestTracer.cs | 23 - src/Api/ILoggingCallback.cs | 37 ++ src/Api/IOneAgentSdk.cs | 120 ++-- src/Api/IOutgoingRemoteCallTracer.cs | 29 +- src/Api/IOutgoingTaggable.cs | 40 +- src/Api/ITracer.cs | 121 ++-- src/Api/Infos/DatabaseInfo.cs | 25 +- src/DummyImpl/DummyDatabaseInfo.cs | 22 +- src/DummyImpl/DummyDatabaseRequestTracer.cs | 37 +- .../DummyIncomingRemoteCallTracer.cs | 31 +- .../DummyOutgoingRemoteCallTracer.cs | 59 ++ src/DummyImpl/OneAgentSDKDummy.cs | 57 +- src/Dynatrace.OneAgent.Sdk.csproj | 24 +- src/OneAgentSDKFactory.cs | 25 +- 28 files changed, 1466 insertions(+), 725 deletions(-) rename Dynatrace.OneAgent.Sdk.sln => sample/Dynatrace.OneAgent.Sdk.Sample.sln (58%) create mode 100644 sample/Dynatrace.OneAgent.Sdk.Sample/CombinedSamples.cs delete mode 100644 sample/Dynatrace.OneAgent.Sdk.Sample/Program.cs create mode 100644 sample/Dynatrace.OneAgent.Sdk.Sample/SampleApplication.cs delete mode 100644 src/Api/IIncomingWebRequestTracer.cs create mode 100644 src/Api/ILoggingCallback.cs create mode 100644 src/DummyImpl/DummyOutgoingRemoteCallTracer.cs diff --git a/.gitignore b/.gitignore index 9c455c3..1dae700 100644 --- a/.gitignore +++ b/.gitignore @@ -221,7 +221,7 @@ orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk +*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) @@ -320,3 +320,7 @@ ASALocalRun/ # MSBuild Binary and Structured Log *.binlog + +.vscode/* +.gradle/ +.project diff --git a/readme.md b/readme.md index 5019bf1..65b583f 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,8 @@ # Dynatrace OneAgent SDK for .NET -This SDK allows Dynatrace customers to instrument .NET applications. This is useful to enhance the visibility for proprietary frameworks or custom frameworks not directly supported by [Dynatrace OneAgent](https://www.dynatrace.com/technologies/net-monitoring/) out-of-the-box. +This SDK allows Dynatrace customers to instrument .NET applications. This is useful to enhance the visibility for proprietary frameworks +or custom frameworks not directly supported by [Dynatrace OneAgent](https://www.dynatrace.com/technologies/net-monitoring/) out-of-the-box. This is the official .NET implementation of the [Dynatrace OneAgent SDK](https://github.com/Dynatrace/OneAgent-SDK). @@ -18,25 +19,30 @@ This is the official .NET implementation of the [Dynatrace OneAgent SDK](https:/ * [Tracers](#tracers) * [Features](#features) * [Trace SQL database requests](#trace-sql-database-requests) -* [Administrative Apis](#administrative-apis) + * [Trace remote calls](#trace-remote-calls) + * [Logging callback](#logging-callback) * [Further reading](#further-readings) -* [Help & Support](#help-support) +* [Help & Support](#help--support) * [Release notes](#release-notes) ## Package contents -* `samples`: sample applications, which demonstrates the usage of the SDK. -* `src`: source code of the SDK -* `LICENSE`: license under which the whole SDK and sample applications are published +* `samples`: sample application which demonstrates the usage of the SDK +* `src`: source code of the SDK (API and implementation stub - for reference only, not intended to be edited/extended/built by the user) +* `LICENSE`: license under which the SDK and sample applications are published + +The SDK implementation is provided by the installed OneAgent at runtime. The classes in `src/DummyImpl` are a stub that is used if no +OneAgent is installed on the host so that your application is not affected by any missing OneAgent dependency. ## Requirements * Dynatrace OneAgent (required versions see below) -* Any .NET Full framework or .NET Core version that supports .NET Standard 1.0 +* .NET Full Framework >= 4.5 or .NET Core >= 1.0 (the SDK is built using .NET Standard 1.0) |OneAgent SDK for .NET|Required OneAgent version| |:-----------------------|:------------------------| -|1.0.x |>=1.153 | +|1.0.0-alpha |1.153-1.155 | +|1.1.0-alpha |>=1.157 | ## Integration @@ -50,28 +56,29 @@ If you want to integrate the OneAgent SDK into your application, just add the fo The Dynatrace OneAgent SDK for .NET has no further dependencies. - ### Troubleshooting * Make sure OneAgent is installed and running on the host monitoring your application * Make sure process monitoring is enabled +* Ensure that you have set the OneAgent SDK logging callback and check its output ## API Concepts Common concepts of the Dynatrace OneAgent SDK are explained the [Dynatrace OneAgent SDK repository](https://github.com/Dynatrace/OneAgent-SDK). -### OneAgentSDK object +### IOneAgentSdk object -Use OneAgentSDKFactory.CreateInstance() to obtain an OneAgentSDK instance. You should reuse this object over the whole application and if possible CLR lifetime: +Use `OneAgentSdkFactory.CreateInstance` to obtain an OneAgentSDK instance. +You should reuse this object over the whole application and if possible CLR lifetime: ```csharp -OneAgentSdk oneAgentSdk = OneAgentSdkFactory.CreateInstance(); +IOneAgentSdk oneAgentSdk = OneAgentSdkFactory.CreateInstance(); ``` ### Tracers -To trace any kind of call you first need to create a Tracer. The Tracer object represents the logical and physical endpoint that you want to call. A Tracer serves two purposes. First to time the call (duraction, cpu and more) and report errors. That is why each Tracer has these three methods. The error method must be called only once, and it must be in between start and end. +To trace any kind of call you first need to create a Tracer. The Tracer object represents the logical and physical endpoint that you want to call. A Tracer serves two purposes. First to time the call (duration, cpu and more) and report errors. That is why each Tracer has these three methods. The `Error` method must be called only once, and it must be in between `Start` and `End`. Each Tracer can only be used once and you need to create a new instance for each request/call that you want to trace (i.e., `Start` cannot be called twice on the same instance). ```csharp @@ -91,11 +98,11 @@ Sample usage: ```csharp public static async Task SampleMethodAsync() { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); + IOneAgentSdk oneAgentSdk = OneAgentSdkFactory.CreateInstance(); + IDatabaseInfo dbInfo = oneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "MyChannelEndpoint"); + IDatabaseRequestTracer dbTracer = oneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); - dbTracer.StartAsync(); //instead of Start() we call the StartAsync() method + await dbTracer.StartAsync(); // instead of Start() we call the StartAsync() method try { await DatabaseApi.AsyncDatabaseCall(); @@ -110,31 +117,28 @@ public static async Task SampleMethodAsync() } } ``` -Additionally the .NET OneAgent SDK also offers a convenient Trace() method with multiple overloads. This method can be called in both asynchronous and synchronous methods. In case of an async method you can pass the given async method to the Trace method and await on the result of the Trace method. +Additionally the SDK also offers a convenient `Trace` method. This method can be called in both asynchronous and synchronous methods. In case of an async method you can pass the given async method to the `TraceAsync` method and await on the result of the `TraceAsync` method. Sample usage: ```csharp public static async Task SampleMethodAsync() { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); + IOneAgentSdk oneAgentSdk = OneAgentSdkFactory.CreateInstance(); + IDatabaseInfo dbInfo = oneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "MyChannelEndpoint"); + IDatabaseRequestTracer dbTracer = oneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); - var result = await dbTracer.Trace(() => DatabaseApi.AsyncDatabaseCall()); + var result = await dbTracer.TraceAsync(() => DatabaseApi.AsyncDatabaseCall()); } ``` -The Trace method internally calls the Start or StartAsync and the End method, and in case of an exception it also calls the Error method. Additionally, it also takes care of collecting timing information across threads in case of the C# async method is executed on multiple threads. - -The Trace method with its overloads supports both synchronous and asynchronous methods. -So, to summarize this, in case of -* synchronous methods you can either use the Start(), End(), and Error() methods, or the convenient Trace() method, -* asynchronous methods you can either use the StartAsync(), End(), and Error() methods, or the convenient Trace() method. +The `Trace` method internally calls the `Start` method and the `TraceAsync` method calls `StartAsync`. In case of an exception they also call the `Error` method. Both finally call the `End` method. Additionally, they also take care of collecting timing information across threads in case the C# async method is executed on multiple threads. +To summarize this, in case of +* synchronous methods you can either use the `Start`, `End` and `Error` methods, or the convenience method `Trace`, +* asynchronous methods you can either use the `StartAsync`, `End` and `Error` methods, or the convenience method `TraceAsync`. -The second purpose of a Tracer is to allow tracing across process boundaries. - +To allow tracing across process and technology boundaries, tracers can be supplied with so-called tags. Tags are strings or byte arrays generated by the SDK that enable Dynatrace to trace a transaction end-to-end. The user has to take care of transporting the tag from one process to the other. ## Features @@ -143,75 +147,146 @@ The feature sets differ slightly with each language implementation. More functio A more detailed specification of the features can be found in [Dynatrace OneAgent SDK](https://github.com/Dynatrace/OneAgent-SDK). |Feature |Required OneAgent SDK for .NET version| -|:------ |:----------------------------------------| -|Trace SQL database requests |>=1.0.0 | +|:------ |:--------------------------------------| +|Trace SQL database requests |>=1.0.0-alpha | +|Logging callback |>=1.1.0-alpha | +|Trace remote calls |>=1.1.0-alpha | ### Trace SQL database requests -A SQL database request is traced by calling TraceSQLDatabaseRequest(). See [DatabaseRequestTracerSamples.cs](/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs) for the full list of examples (sync/async/lambda/exception/...) +A SQL database request is traced by calling `TraceSQLDatabaseRequest`. See [DatabaseRequestTracerSamples.cs](/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs) for the full list of examples (sync/async/lambda/exception/...) **Example synchronous database call (see [DatabaseRequestTracerSamples.cs](/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs) for more details):** ```csharp -var instance = OneAgentSdkFactory.CreateInstance(); - -var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); -var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); +IDatabaseInfo dbInfo = oneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); +IDatabaseRequestTracer dbTracer = oneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); dbTracer.Start(); try { - VoidMethod(); + ExecuteDbCallVoid(); } catch { - dbTracer.Error("DB call failed"); + dbTracer.Error("DB call failed"); + // handle or rethrow } finally { - dbTracer.End(); + dbTracer.End(); } ``` **Example asynchronous database call (see [DatabaseRequestTracerSamples.cs](/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs) for more details):** ```csharp -var instance = OneAgentSdkFactory.CreateInstance(); -var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); -var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); +IDatabaseInfo dbInfo = oneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); +IDatabaseRequestTracer dbTracer = oneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); -dbTracer.StartAsync(); +await dbTracer.StartAsync(); try { - await VoidTask(); + await ExecuteDbCallVoidAsync(); } catch { - dbTracer.Error("DB call failed"); + dbTracer.Error("DB call failed"); + // handle or rethrow } finally { - dbTracer.End(); + dbTracer.End(); } ``` **Example tracing database call in a async lambda expression (see [DatabaseRequestTracerSamples.cs](/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs) for more details):** ```csharp -var instance = OneAgentSdkFactory.CreateInstance(); -var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); -var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); +IDatabaseInfo dbInfo = oneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); +IDatabaseRequestTracer dbTracer = oneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + +int res = dbTracer.Trace(() => ExecuteDbCallInt()); +``` + +### Trace remote calls + +You can use the SDK to trace proprietary IPC communication from one process to the other. 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, as such you need to supply the name of the remote service and remote method. In addition you need to transport the tag in your remote call to the server side if you want to trace it end-to-end. + +```csharp +IOutgoingRemoteCallTracer outgoingRemoteCallTracer = oneAgentSdk.TraceOutgoingRemoteCall( + "RemoteMethod", "RemoteServiceName", + "mrcp://endpoint/service", ChannelType.TCP_IP, "myRemoteHost:1234"); +outgoingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + +outgoingRemoteCallTracer.Start(); +try +{ + string tag = outgoingRemoteCallTracer.GetDynatraceStringTag(); + // make the call and transport the tag across to server +} +catch (Exception e) +{ + outgoingRemoteCallTracer.Error(e.Message); + // handle or rethrow +} +finally +{ + outgoingRemoteCallTracer.End(); +} +``` + +On the server side you need to wrap the handling and processing of your remote call as well. This will not only trace the server side call and everything that happens, it will also connect it to the calling side. + +```csharp +IIncomingRemoteCallTracer incomingRemoteCallTracer = oneAgentSdk + .TraceIncomingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service"); + +string incomingDynatraceStringTag = ...; // retrieve from incoming call metadata +incomingRemoteCallTracer.SetDynatraceStringTag(incomingDynatraceStringTag); -var res = await dbTracer.Trace(() => IntTask()); +incomingRemoteCallTracer.Start(); +try +{ + incomingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + ProcessRemoteCall(); +} +catch (Exception e) +{ + incomingRemoteCallTracer.Error(e.Message); + // handle or rethrow +} +finally +{ + incomingRemoteCallTracer.End(); +} ``` +### Logging callback + +The SDK provides a logging-callback to give information back to the calling application in case of an error. The user application has to provide a callback like the following: + +```csharp +class StdErrLoggingCallback : ILoggingCallback +{ + public void Error(string message) => Console.WriteLine("[OneAgent SDK] Error: " + message); + public void Warn(string message) => Console.WriteLine("[OneAgent SDK] Warning: " + message); +} -### Administrative Apis +public static void Main(string[] args) +{ + IOneAgentSdk oneAgentSdk = OneAgentSdkFactory.CreateInstance(); + var loggingCallback = new StdErrLoggingCallback(); + oneAgentSdk.SetLoggingCallback(loggingCallback); +} +``` -not yet available +In general it is a good idea to forward these logging events to your application specific logging framework. ## Further readings @@ -220,14 +295,14 @@ not yet available ## Help & Support -The Dynatrace OneAgent SDK for .NET is an open source project, currently in early access status (EAP). +The Dynatrace OneAgent SDK for .NET is an open source project, currently in beta status. ### Get Help * Ask a question in the [product forums](https://answers.dynatrace.com/spaces/482/view.html) * Read the [product documentation](https://www.dynatrace.com/support/help/) -### Open a [GitHub issue](https://github.com/Dynatrace/OneAgent-SDK-for-Java/issues) to +### Open a [GitHub issue](https://github.com/Dynatrace/OneAgent-SDK-for-dotnet/issues) to * Report minor defects, minor items or typos * Ask for improvements or changes in the SDK API @@ -239,6 +314,7 @@ SLAs don't apply for GitHub tickets see also [Releases](https://github.com/Dynatrace/OneAgent-SDK-for-dotnet/releases) -|Version|Description | -|:------|:-------------------------------------------| -|1.0.0 |Initial release | +|Version |Description | +|:----------|:--------------------------------------------| +|1.0.0-alpha|EAP release | +|1.1.0-alpha|Adds remote call tracing and logging callback| diff --git a/Dynatrace.OneAgent.Sdk.sln b/sample/Dynatrace.OneAgent.Sdk.Sample.sln similarity index 58% rename from Dynatrace.OneAgent.Sdk.sln rename to sample/Dynatrace.OneAgent.Sdk.Sample.sln index 21966b9..5134898 100644 --- a/Dynatrace.OneAgent.Sdk.sln +++ b/sample/Dynatrace.OneAgent.Sdk.Sample.sln @@ -1,31 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dynatrace.OneAgent.Sdk", "src\Dynatrace.OneAgent.Sdk.csproj", "{A8128352-47FA-4BDA-8BF5-CFFCA7C16F97}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dynatrace.OneAgent.Sdk.Sample", "sample\Dynatrace.OneAgent.Sdk.Sample\Dynatrace.OneAgent.Sdk.Sample.csproj", "{B47F5422-23F6-4FDC-8E16-ED41FDD76993}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A8128352-47FA-4BDA-8BF5-CFFCA7C16F97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8128352-47FA-4BDA-8BF5-CFFCA7C16F97}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8128352-47FA-4BDA-8BF5-CFFCA7C16F97}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8128352-47FA-4BDA-8BF5-CFFCA7C16F97}.Release|Any CPU.Build.0 = Release|Any CPU - {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {0E3F7DC6-9C05-41CA-A5A4-E1420CB4A095} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dynatrace.OneAgent.Sdk.Sample", "Dynatrace.OneAgent.Sdk.Sample\Dynatrace.OneAgent.Sdk.Sample.csproj", "{B47F5422-23F6-4FDC-8E16-ED41FDD76993}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B47F5422-23F6-4FDC-8E16-ED41FDD76993}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0E3F7DC6-9C05-41CA-A5A4-E1420CB4A095} + EndGlobalSection +EndGlobal diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/CombinedSamples.cs b/sample/Dynatrace.OneAgent.Sdk.Sample/CombinedSamples.cs new file mode 100644 index 0000000..eb6b2b9 --- /dev/null +++ b/sample/Dynatrace.OneAgent.Sdk.Sample/CombinedSamples.cs @@ -0,0 +1,79 @@ +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using Dynatrace.OneAgent.Sdk.Api; +using Dynatrace.OneAgent.Sdk.Api.Enums; +using System; +using System.Threading; + +namespace Dynatrace.OneAgent.Sdk.Sample +{ + class CombinedSamples + { + public static void RemoteCallWithDatabase() + { + IOutgoingRemoteCallTracer outgoingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceOutgoingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service", ChannelType.TCP_IP, "myRemoteHost:1234"); + outgoingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + + outgoingRemoteCallTracer.Start(); + try + { + string outgoingDynatraceStringTag = outgoingRemoteCallTracer.GetDynatraceStringTag(); + // make the call and transport the tag across to server + + // represents server side processing + Thread server = new Thread(() => + { + IIncomingRemoteCallTracer incomingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceIncomingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service"); + + string incomingDynatraceStringTag = outgoingDynatraceStringTag; // retrieve from incoming call metadata + incomingRemoteCallTracer.SetDynatraceStringTag(incomingDynatraceStringTag); + + incomingRemoteCallTracer.Start(); + try + { + incomingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + + // execute database request on server + DatabaseRequestTracerSamples.Sync_StartEnd(); + } + catch (Exception e) + { + incomingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + incomingRemoteCallTracer.End(); + } + }); + server.Start(); + server.Join(); // sync call, wait for db result + } + catch (Exception e) + { + outgoingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + outgoingRemoteCallTracer.End(); + } + } + } +} diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs b/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs index 1240c9c..094ab32 100644 --- a/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs +++ b/sample/Dynatrace.OneAgent.Sdk.Sample/DatabaseRequestTracerSamples.cs @@ -1,259 +1,289 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api; +using Dynatrace.OneAgent.Sdk.Api.Enums; +using Dynatrace.OneAgent.Sdk.Api.Infos; +using System; +using System.Threading; +using System.Threading.Tasks; namespace Dynatrace.OneAgent.Sdk.Sample { - /// - /// Contains samples that use the IDatabaseRequestTracer. - /// - /// Method name convention: - /// [Sync|Async]_[Exception|NoException]_[StartEnd|StartAsyncEnd|Lambda]_(And) - /// Example: a method that simulates an async db call, which throws an exception and uses the Trace method with a lambda: - /// Async_Exception_Lambda - /// Example2: a method that simulates 2 db calls, the first is a sync call that doesn't throw an exception and uses the Start() and End() method, - /// the second one is an async that throws an exception and uses the Trace method with a lambda: - /// Sync_NoException_StartEnd_And_Async_Exception_Lambda - /// - public static class DatabaseRequestTracerSamples - { - public static void Sync_NoException_StartEnd() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - dbTracer.Start(); - try - { - VoidMethod(); - } - catch - { - dbTracer.Error("DB call failed"); - } - finally - { - dbTracer.End(); - } - } - - public static async Task Async_NoException_StartEnd() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - dbTracer.StartAsync(); - try - { - await VoidTask(); - } - catch - { - dbTracer.Error("DB call failed"); - } - finally - { - dbTracer.End(); - } - } - - public static async Task Async_NoException_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - var res = await dbTracer.Trace(() => IntTask()); - } - - public static void Sync_NoException_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - var res = dbTracer.Trace(() => IntMethod()); - } - - public static async Task Async_NoException_Lambda_And_Async_NoException_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - var res = await dbTracer.Trace(() => IntTask()); - - var instance2 = OneAgentSdkFactory.CreateInstance(); - var dbinfo2 = instance.CreateDatabaseInfo("MyDb2", "MyVendor2", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer2 = instance.TraceSQLDatabaseRequest(dbinfo2, "Select * From AA"); - - var res2 = await dbTracer2.Trace(() => IntTask()); - } - - public static async Task Async_NoException_StartAsyncEnd_And_Async_NoException_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - dbTracer.StartAsync(); - await VoidTask(); - dbTracer.End(); - - - var instance2 = OneAgentSdkFactory.CreateInstance(); - var dbinfo2 = instance.CreateDatabaseInfo("MyDb2", "MyVendor2", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer2 = instance.TraceSQLDatabaseRequest(dbinfo2, "Select * From AA"); - var res2 = await dbTracer2.Trace(() => IntTask()); - } - - public static async Task Async_Exception_StartAsyncEnd() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - dbTracer.StartAsync(); - try - { - await VoidTaskWithException(); - } - catch - { - dbTracer.Error("DB call failed"); - } - finally - { - dbTracer.End(); - } - } - - public static async Task Async_Exception_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - try - { - await dbTracer.Trace(() => VoidTaskWithException()); - } - catch (Exception e) - { - Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda)}, Message: {e.Message}"); - } - } - - public static async Task Async_Exception_Lambda_And_Async_Exception_Lambda() - { - - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - try - { - await dbTracer.Trace(() => VoidTaskWithException()); - } - catch (Exception e) - { - Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda_And_Async_Exception_Lambda)}, Message: {e.Message}"); - } - - var instance2 = OneAgentSdkFactory.CreateInstance(); - var dbinfo2 = instance2.CreateDatabaseInfo("MyDb2", "MyVendor2", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer2 = instance2.TraceSQLDatabaseRequest(dbinfo2, "Select2 * From AA"); - - try - { - var result = await dbTracer2.Trace(() => IntTaskWithException()); - } - catch (Exception e) - { - Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda_And_Async_Exception_Lambda)}, Message: {e.Message}"); - } - } - - public static async Task Async_NoException_Lambda_And_Sync_Exception_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - await dbTracer.Trace(() => IntTask()); - - var instance2 = OneAgentSdkFactory.CreateInstance(); - var dbinfo2 = instance2.CreateDatabaseInfo("MyDb2", "MyVendor2", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer2 = instance2.TraceSQLDatabaseRequest(dbinfo2, "Select2 * From AA"); - - try - { - var result = dbTracer2.Trace(() => IntMethodWithException()); - } - catch (Exception e) - { - Console.WriteLine($"Exception in {nameof(Async_NoException_Lambda_And_Sync_Exception_Lambda)}, Message: {e.Message}"); - } - } - - public static async Task Sync_Exception_Lambda_And_Async_NoException_Lambda() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var dbinfo = instance.CreateDatabaseInfo("MyDb", "MyVendor", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer = instance.TraceSQLDatabaseRequest(dbinfo, "Select * From AA"); - - try - { - dbTracer.Trace(() => VoidMethodWithException()); - } - catch (Exception e) - { - Console.WriteLine($"Exception in {nameof(Sync_Exception_Lambda_And_Async_NoException_Lambda)}, Message: {e.Message}"); - } - - var instance2 = OneAgentSdkFactory.CreateInstance(); - var dbinfo2 = instance2.CreateDatabaseInfo("MyDb2", "MyVendor2", Dynatrace.OneAgent.Sdk.Api.Enums.ChannelType.TCP_IP, "MyChannelEndpoint"); - var dbTracer2 = instance2.TraceSQLDatabaseRequest(dbinfo2, "Select2 * From AA"); - - var result = await dbTracer2.Trace(() => IntTask()); - } - - #region DbCalls - //these methods simulate DB calls. Imagine that these are methods on a class which is an API to a database. - public static async Task VoidTask() => await Task.Delay(500); //async void - - public static async Task IntTask() => await Task.FromResult(42); //async with return value - - public static int IntMethod() => 42; //sync with return value - - public static void VoidMethod() { Console.WriteLine("VoidMethod runs"); } //sync void - - - //methods with exceptions: - public static async Task VoidTaskWithException() - { - await Task.Delay(500); - throw new Exception("Bammm"); - } - - public static async Task IntTaskWithException() - { - Console.WriteLine("start IntTaskWithException"); - await Task.Delay(200); - throw new Exception("Bamm"); - } - - public static int IntMethodWithException() - { - throw new Exception("Bamm"); - } - - public static void VoidMethodWithException() - { - throw new Exception("Bamm"); - } - - #endregion - } + /// + /// Samples demonstrating how database requests can be traced using + /// + /// + /// In order for these traces to be captured by Dynatrace and shown in the UI you need to create a Custom Service + /// as database requests occurring outside of service methods (i.e., not on a PurePath) are ignored. + /// --> Go to the Dynatrace UI and select [Settings > Server-side service monitoring > Custom service detection > .NET services] + /// There you can add to caputre everything or add + /// each of the desired methods of separately. + /// + public static class DatabaseRequestTracerSamples + { + public static void Sync_StartEnd() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + dbTracer.Start(); + try + { + ExecuteDbCallVoid(); + } + catch + { + dbTracer.Error("DB call failed"); + // handle or rethrow + } + finally + { + dbTracer.End(); + } + } + + public static async Task Async_StartEnd() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + await dbTracer.StartAsync(); + try + { + await ExecuteDbCallVoidAsync(); + } + catch + { + dbTracer.Error("DB call failed"); + // handle or rethrow + } + finally + { + dbTracer.End(); + } + } + + public static void Sync_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + int res = dbTracer.Trace(() => ExecuteDbCallInt()); + } + + public static async Task Async_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + int res = await dbTracer.TraceAsync(() => ExecuteDbCallIntAsync()); + } + + public static async Task Async_Lambda_And_Async_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + int res = await dbTracer.TraceAsync(() => ExecuteDbCallIntAsync()); + + IDatabaseInfo dbInfo2 = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb2", "MyVendor2", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer2 = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo2, "Select * From AA"); + + int res2 = await dbTracer2.TraceAsync(() => ExecuteDbCallIntAsync()); + } + + public static async Task Async_StartAsyncEnd_And_Async_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + await dbTracer.StartAsync(); + await ExecuteDbCallVoidAsync(); + dbTracer.End(); + + IDatabaseInfo dbInfo2 = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb2", "MyVendor2", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer2 = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo2, "Select * From AA"); + + int res2 = await dbTracer2.TraceAsync(() => ExecuteDbCallIntAsync()); + } + + public static async Task Async_Exception_StartAsyncEnd() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + await dbTracer.StartAsync(); + try + { + await ExecuteDbCallVoidExceptionAsync(); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Async_Exception_StartAsyncEnd)}, Message: {e.Message}"); + } + finally + { + dbTracer.End(); + } + } + + public static async Task Async_Exception_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + try + { + await dbTracer.TraceAsync(() => ExecuteDbCallVoidExceptionAsync()); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda)}, Message: {e.Message}"); + } + } + + public static async Task Async_Exception_Lambda_And_Async_Exception_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + try + { + await dbTracer.TraceAsync(() => ExecuteDbCallVoidExceptionAsync()); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda_And_Async_Exception_Lambda)}, Message: {e.Message}"); + } + + IDatabaseInfo dbInfo2 = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb2", "MyVendor2", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer2 = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo2, "Select2 * From AA"); + + try + { + int result = await dbTracer2.TraceAsync(() => ExecuteDbCallIntExceptionAsync()); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Async_Exception_Lambda_And_Async_Exception_Lambda)}, Message: {e.Message}"); + } + } + + public static async Task Async_Lambda_And_Sync_Exception_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + await dbTracer.TraceAsync(() => ExecuteDbCallIntAsync()); + + IDatabaseInfo dbInfo2 = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb2", "MyVendor2", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer2 = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo2, "Select2 * From AA"); + + try + { + int result = dbTracer2.Trace(() => ExecuteDbCallIntException()); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Async_Lambda_And_Sync_Exception_Lambda)}, Message: {e.Message}"); + } + } + + public static async Task Sync_Exception_Lambda_And_Async_Lambda() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + try + { + dbTracer.Trace(() => ExecuteDbCallVoidException()); + } + catch (Exception e) + { + Console.WriteLine($"Exception in {nameof(Sync_Exception_Lambda_And_Async_Lambda)}, Message: {e.Message}"); + } + + IDatabaseInfo dbInfo2 = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb2", "MyVendor2", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer2 = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo2, "Select2 * From AA"); + + int result = await dbTracer2.TraceAsync(() => ExecuteDbCallIntAsync()); + } + + /// + /// tests various misuse cases of the SDK resulting in warnings through the logging callback + /// + public static void Sync_Misuse_LoggingCallbackTest() + { + IDatabaseInfo dbInfo = SampleApplication.OneAgentSdk.CreateDatabaseInfo("MyDb", "MyVendor", ChannelType.TCP_IP, "example.com:12345"); + IDatabaseRequestTracer dbTracer = SampleApplication.OneAgentSdk.TraceSQLDatabaseRequest(dbInfo, "Select * From AA"); + + dbTracer.End(); // Warning: missing Start + dbTracer.Start(); // ok + dbTracer.Start(); // Warning: already started + dbTracer.StartAsync(); // Warning: already started + dbTracer.End(); // ok + dbTracer.SetRoundTripCount(0); // Warning: has to be set before End + dbTracer.SetRowsReturned(0); // Warning: has to be set before End + dbTracer.End(); // Warning: already ended + } + + #region DbCalls + + //these methods simulate DB calls. Imagine that these are methods on a class which is an API to a database. + private static async Task ExecuteDbCallVoidAsync() => await Task.Delay(100); + + private static async Task ExecuteDbCallIntAsync() + { + await Task.Delay(100); + return await Task.FromResult(42); + } + + private static int ExecuteDbCallInt() + { + Thread.Sleep(100); + return 42; + } + + private static void ExecuteDbCallVoid() + { + Thread.Sleep(100); + } + + private static async Task ExecuteDbCallVoidExceptionAsync() + { + await Task.Delay(100); + throw new Exception("Exception occurred."); + } + + private static async Task ExecuteDbCallIntExceptionAsync() + { + await Task.Delay(100); + throw new Exception("Exception occurred."); + } + + private static int ExecuteDbCallIntException() + { + Thread.Sleep(100); + throw new Exception("Exception occurred."); + } + + private static void ExecuteDbCallVoidException() + { + Thread.Sleep(100); + throw new Exception("Exception occurred."); + } + + #endregion + } } diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/Dynatrace.OneAgent.Sdk.Sample.csproj b/sample/Dynatrace.OneAgent.Sdk.Sample/Dynatrace.OneAgent.Sdk.Sample.csproj index 29f8d5d..e46fea8 100644 --- a/sample/Dynatrace.OneAgent.Sdk.Sample/Dynatrace.OneAgent.Sdk.Sample.csproj +++ b/sample/Dynatrace.OneAgent.Sdk.Sample/Dynatrace.OneAgent.Sdk.Sample.csproj @@ -1,16 +1,13 @@ - + Exe - netcoreapp2.0;net46 + netcoreapp1.0;net45 + True - - default - - - - + + diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/Program.cs b/sample/Dynatrace.OneAgent.Sdk.Sample/Program.cs deleted file mode 100644 index fa8119d..0000000 --- a/sample/Dynatrace.OneAgent.Sdk.Sample/Program.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Threading.Tasks; -using Dynatrace.OneAgent.Sdk.Api; - -namespace Dynatrace.OneAgent.Sdk.Sample -{ - public class Program - { - public static void Main(string[] args) - { - Console.WriteLine("Enter test name"); - var testName = Console.ReadLine(); - - //TODO: Find a better solution for this - if (testName == "Sync_NoException_StartEnd") - { - DatabaseRequestTracerSamples.Sync_NoException_StartEnd(); - } - if (testName == "Async_NoException_StartEnd") - { - DatabaseRequestTracerSamples.Async_NoException_StartEnd().Wait(); - } - if (testName == "Async_NoException_Lambda") - { - DatabaseRequestTracerSamples.Async_NoException_Lambda().Wait(); - } - if (testName == "Sync_NoException_Lambda") - { - DatabaseRequestTracerSamples.Sync_NoException_Lambda(); - } - if (testName == "Async_NoException_Lambda_And_Async_NoException_Lambda") - { - DatabaseRequestTracerSamples.Async_NoException_Lambda_And_Async_NoException_Lambda().Wait(); - } - if (testName == "Async_NoException_StartAsyncEnd_And_Async_NoException_Lambda") - { - DatabaseRequestTracerSamples.Async_NoException_StartAsyncEnd_And_Async_NoException_Lambda().Wait(); - } - if (testName == "Async_Exception_StartAsyncEnd") - { - DatabaseRequestTracerSamples.Async_Exception_StartAsyncEnd().Wait(); - } - if (testName == "Async_Exception_Lambda") - { - DatabaseRequestTracerSamples.Async_Exception_Lambda().Wait(); - } - if (testName == "Async_Exception_Lambda_And_Async_Exception_Lambda") - { - DatabaseRequestTracerSamples.Async_Exception_Lambda_And_Async_Exception_Lambda().Wait(); - } - if (testName == "Async_NoException_Lambda_And_Sync_Exception_Lambda") - { - DatabaseRequestTracerSamples.Async_NoException_Lambda_And_Sync_Exception_Lambda().Wait(); - } - if (testName == "Sync_Exception_Lambda_And_Async_NoException_Lambda") - { - DatabaseRequestTracerSamples.Sync_Exception_Lambda_And_Async_NoException_Lambda().Wait(); - } - - if(testName == "SimpleIncomingRemoting") - { - RemoteCallTracerSamples.SimpleIncomingRemoting(); - } - - Console.WriteLine("Done, press any key to exit"); - Console.Read(); - } - } -} diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/RemoteCallTracerSamples.cs b/sample/Dynatrace.OneAgent.Sdk.Sample/RemoteCallTracerSamples.cs index 852e8da..0ce5c2c 100644 --- a/sample/Dynatrace.OneAgent.Sdk.Sample/RemoteCallTracerSamples.cs +++ b/sample/Dynatrace.OneAgent.Sdk.Sample/RemoteCallTracerSamples.cs @@ -1,28 +1,189 @@ -using System; -using System.Collections.Generic; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api; +using Dynatrace.OneAgent.Sdk.Api.Enums; +using System; +using System.Threading; namespace Dynatrace.OneAgent.Sdk.Sample { class RemoteCallTracerSamples { - public static void SimpleIncomingRemoting() - { - var instance = OneAgentSdkFactory.CreateInstance(); - var incomingRemoteCallTracer = instance.TraceIncomingRemoteCall("TestMethod", "testService", "testEndpoint"); - - incomingRemoteCallTracer.Start(); - - Random rnd = new Random(); - int sum = 0; - for (int i = 0; i < 1000; i++) - { - sum += rnd.Next(-10,10); - } - - Console.WriteLine(sum); - incomingRemoteCallTracer.End(); - } + public static void OutgoingRemoteCall() + { + IOutgoingRemoteCallTracer outgoingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceOutgoingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service", ChannelType.TCP_IP, "myRemoteHost:1234"); + outgoingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + + outgoingRemoteCallTracer.Start(); + try + { + string outgoingDynatraceStringTag = outgoingRemoteCallTracer.GetDynatraceStringTag(); + // make the call and transport the tag across to server + } + catch (Exception e) + { + outgoingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + outgoingRemoteCallTracer.End(); + } + } + + public static void IncomingRemoteCall() + { + IIncomingRemoteCallTracer incomingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceIncomingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service"); + + string incomingDynatraceStringTag = string.Empty; // retrieve from incoming call metadata + incomingRemoteCallTracer.SetDynatraceStringTag(incomingDynatraceStringTag); + + incomingRemoteCallTracer.Start(); + try + { + incomingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + ProcessRemoteCall(); + } + catch (Exception e) + { + incomingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + incomingRemoteCallTracer.End(); + } + } + + /// + /// Demonstrates an outgoing remote call originating from a client and being process by a server. + /// The Dynatrace tag is used to link both calls together. + /// + public static void LinkedSyncRemoteCall() + { + IOutgoingRemoteCallTracer outgoingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceOutgoingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service", ChannelType.TCP_IP, "myRemoteHost:1234"); + outgoingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + + outgoingRemoteCallTracer.Start(); + try + { + string outgoingDynatraceStringTag = outgoingRemoteCallTracer.GetDynatraceStringTag(); + // make the call and transport the tag across to server + + // represents server side processing + Thread server = new Thread(() => + { + IIncomingRemoteCallTracer incomingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceIncomingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service"); + + string incomingDynatraceStringTag = outgoingDynatraceStringTag; // retrieve from incoming call metadata + incomingRemoteCallTracer.SetDynatraceStringTag(incomingDynatraceStringTag); + + incomingRemoteCallTracer.Start(); + try + { + incomingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + ProcessRemoteCall(); + } + catch (Exception e) + { + incomingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + incomingRemoteCallTracer.End(); + } + }); + server.Start(); + server.Join(); // sync remote call, wait for result + } + catch (Exception e) + { + outgoingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + outgoingRemoteCallTracer.End(); + } + } + + /// + /// Demonstrates an outgoing remote call originating from a client and being process by a server. + /// The Dynatrace tag is used to link both calls together. + /// + public static void LinkedAsyncRemoteCall() + { + IOutgoingRemoteCallTracer outgoingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceOutgoingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service", ChannelType.TCP_IP, "myRemoteHost:1234"); + outgoingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + + outgoingRemoteCallTracer.Start(); + try + { + string outgoingDynatraceStringTag = outgoingRemoteCallTracer.GetDynatraceStringTag(); + // make the call and transport the tag across to server + + // represents server side processing + Thread server = new Thread(() => + { + IIncomingRemoteCallTracer incomingRemoteCallTracer = SampleApplication.OneAgentSdk + .TraceIncomingRemoteCall("RemoteMethod", "RemoteServiceName", "mrcp://endpoint/service"); + + string incomingDynatraceStringTag = outgoingDynatraceStringTag; // retrieve from incoming call metadata + incomingRemoteCallTracer.SetDynatraceStringTag(incomingDynatraceStringTag); + + incomingRemoteCallTracer.Start(); + try + { + incomingRemoteCallTracer.SetProtocolName("MyRemoteCallProtocol"); + ProcessRemoteCall(); + } + catch (Exception e) + { + incomingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + incomingRemoteCallTracer.End(); + } + }); + server.Start(); + // async processing on server + } + catch (Exception e) + { + outgoingRemoteCallTracer.Error(e.Message); + // handle or rethrow + } + finally + { + outgoingRemoteCallTracer.End(); + } + } + + private static void ProcessRemoteCall() + { + Thread.Sleep(100); + } } } diff --git a/sample/Dynatrace.OneAgent.Sdk.Sample/SampleApplication.cs b/sample/Dynatrace.OneAgent.Sdk.Sample/SampleApplication.cs new file mode 100644 index 0000000..8cd5c04 --- /dev/null +++ b/sample/Dynatrace.OneAgent.Sdk.Sample/SampleApplication.cs @@ -0,0 +1,124 @@ +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using Dynatrace.OneAgent.Sdk.Api; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace Dynatrace.OneAgent.Sdk.Sample +{ + class StdErrLoggingCallback : ILoggingCallback + { + public void Error(string message) => Console.Error.WriteLine("[OneAgent SDK] Error: " + message); + + public void Warn(string message) => Console.Error.WriteLine("[OneAgent SDK] Warning: " + message); + } + + public class SampleApplication + { + private static readonly Lazy _oneAgentSdk = new Lazy(() => + { + IOneAgentSdk instance = OneAgentSdkFactory.CreateInstance(); + instance.SetLoggingCallback(new StdErrLoggingCallback()); + return instance; + }); + + /// + /// shared instance of for our sample application + /// + public static IOneAgentSdk OneAgentSdk => _oneAgentSdk.Value; + + /// + /// CLI for executing the samples provided in the various sample classes + /// not related to the SDK or its usage + /// + public static void Main(string[] args) + { + var testClasses = new[] + { + typeof(DatabaseRequestTracerSamples), + typeof(RemoteCallTracerSamples), + typeof(CombinedSamples) + }; + var testMethods = GetTestMethods(testClasses).ToList(); + var groups = from t in testMethods + group t.Name by t.DeclaringType.FullName into g + select new { TestClass = g.Key, TestMethods = g.ToList() }; + + var index = 1; + Console.WriteLine("Available samples:"); + foreach (var g in groups) + { + Console.WriteLine($"\n[{g.TestClass}]"); + foreach (var m in g.TestMethods) + { + Console.WriteLine($"\t{index++}: {m}"); + } + } + Console.WriteLine("\n---------------------------------------------------------------\n"); + while (true) + { + Console.WriteLine($"Enter sample index (e.g. '1') or fully qualified method name (or press Enter to exit):"); + Console.Write("> "); + string testName = Console.ReadLine()?.Trim(); + if (string.IsNullOrEmpty(testName) || testName == "q") + { + return; + } + var mi = GetMethodInfoForTestName(testMethods, testName); + if (mi != null) + { + Console.WriteLine($"Invoking {mi.DeclaringType.Name}.{mi.Name}"); + object ret = mi.Invoke(null, null); + (ret as Task)?.Wait(); + Console.WriteLine("Done\n"); + } + else + { + Console.WriteLine($"Test '{testName}' not found."); + Console.WriteLine("Please provide a qualified test name ('TestClass.TestMethod') or its index"); + } + } + } + + private static IEnumerable GetTestMethods(IEnumerable testClasses) + { + return testClasses.SelectMany( + t => t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public)); + } + + private static MethodInfo GetMethodInfoForTestName(List testMethods, string testName) + { + MethodInfo mi; + if (int.TryParse(testName, out var i)) + { + mi = testMethods.ElementAtOrDefault(i - 1); + } + else + { + mi = testMethods.FirstOrDefault(m => + { + var fqn = $"{m.DeclaringType.FullName}.{m.Name}"; + return fqn.Equals(testName, StringComparison.CurrentCultureIgnoreCase); + }); + } + return mi; + } + } +} diff --git a/src/Api/Enums/ChannelType.cs b/src/Api/Enums/ChannelType.cs index 62aadc2..976ce40 100644 --- a/src/Api/Enums/ChannelType.cs +++ b/src/Api/Enums/ChannelType.cs @@ -1,11 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma warning disable CS1591 namespace Dynatrace.OneAgent.Sdk.Api.Enums { - public enum ChannelType + /// + /// Enumerates all well-known communication channel types. + /// + public enum ChannelType { OTHER, TCP_IP, @@ -14,3 +29,4 @@ public enum ChannelType IN_PROCESS } } +#pragma warning restore CS1591 diff --git a/src/Api/Enums/DatabaseVendor.cs b/src/Api/Enums/DatabaseVendor.cs index d28352a..214bae8 100644 --- a/src/Api/Enums/DatabaseVendor.cs +++ b/src/Api/Enums/DatabaseVendor.cs @@ -1,50 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma warning disable CS1591 namespace Dynatrace.OneAgent.Sdk.Api.Enums { - /// - /// Encapsulates database vendor names that are known to Dynatrace. - /// - public static class DatabaseVendor + /// + /// Enumerates all well-known database vendors. Used for + /// Using these constants ensures that services captured by OneAgentSDK are handled the same way as traced via built-in sensors. + /// + public static class DatabaseVendor { - public static String APACHE_HIVE => "ApacheHive"; - public static String CLOUDSCAPE => "Cloudscape"; - public static String HSQLDB => "HSQLDB"; - public static String PROGRESS => "Progress"; - public static String MAXDB => "MaxDB"; - public static String HANADB => "HanaDB"; - public static String INGRES => "Ingres"; - public static String FIRST_SQL => "FirstSQL"; - public static String ENTERPRISE_DB => "EnterpriseDB"; - public static String CACHE => "Cache"; - public static String ADABAS => "Adabas"; - public static String FIREBIRD => "Firebird"; - public static String DB2 => "DB2"; - public static String DERBY_CLIENT => "Derby Client"; - public static String DERBY_EMBEDDED => "Derby Embedded"; - public static String FILEMAKER => "Filemaker"; - public static String INFORMIX => "Informix"; - public static String INSTANT_DB => "InstantDb"; - public static String INTERBASE => "Interbase"; - public static String MYSQL => "MySQL"; - public static String MARIADB => "MariaDB"; - public static String NETEZZA => "Netezza"; - public static String ORACLE => "Oracle"; - public static String PERVASIVE => "Pervasive"; - public static String POINTBASE => "Pointbase"; - public static String POSTGRESQL => "PostgreSQL"; - public static String SQLSERVER => "SQL Server"; - public static String SQLITE => "sqlite"; - public static String SYBASE => "Sybase"; - public static String TERADATA => "Teradata"; - public static String VERTICA => "Vertica"; - public static String CASSANDRA => "Cassandra"; - public static String H2 => "H2"; - public static String COLDFUSION_IMQ => "ColdFusion IMQ"; - public static String REDSHIFT => "Amazon Redshift"; - public static String COUCHBASE => "Couchbase"; - } -} \ No newline at end of file + public static string APACHE_HIVE => "ApacheHive"; + public static string CLOUDSCAPE => "Cloudscape"; + public static string HSQLDB => "HSQLDB"; + public static string PROGRESS => "Progress"; + public static string MAXDB => "MaxDB"; + public static string HANADB => "HanaDB"; + public static string INGRES => "Ingres"; + public static string FIRST_SQL => "FirstSQL"; + public static string ENTERPRISE_DB => "EnterpriseDB"; + public static string CACHE => "Cache"; + public static string ADABAS => "Adabas"; + public static string FIREBIRD => "Firebird"; + public static string DB2 => "DB2"; + public static string DERBY_CLIENT => "Derby Client"; + public static string DERBY_EMBEDDED => "Derby Embedded"; + public static string FILEMAKER => "Filemaker"; + public static string INFORMIX => "Informix"; + public static string INSTANT_DB => "InstantDb"; + public static string INTERBASE => "Interbase"; + public static string MYSQL => "MySQL"; + public static string MARIADB => "MariaDB"; + public static string NETEZZA => "Netezza"; + public static string ORACLE => "Oracle"; + public static string PERVASIVE => "Pervasive"; + public static string POINTBASE => "Pointbase"; + public static string POSTGRESQL => "PostgreSQL"; + public static string SQLSERVER => "SQL Server"; + public static string SQLITE => "sqlite"; + public static string SYBASE => "Sybase"; + public static string TERADATA => "Teradata"; + public static string VERTICA => "Vertica"; + public static string CASSANDRA => "Cassandra"; + public static string H2 => "H2"; + public static string COLDFUSION_IMQ => "ColdFusion IMQ"; + public static string REDSHIFT => "Amazon Redshift"; + public static string COUCHBASE => "Couchbase"; + } +} +#pragma warning restore CS1591 diff --git a/src/Api/IDatabaseRequestTracer.cs b/src/Api/IDatabaseRequestTracer.cs index c7aae75..6965f1d 100644 --- a/src/Api/IDatabaseRequestTracer.cs +++ b/src/Api/IDatabaseRequestTracer.cs @@ -1,25 +1,39 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api { - public interface IDatabaseRequestTracer : ITracer + /// + /// Interface for outgoing database tracer. + /// + public interface IDatabaseRequestTracer : ITracer { /// - /// Adds optional information about retrieved rows of the traced database request. Must be set before end() - /// of this tracer is being called. + /// Adds optional information about retrieved rows of the traced database request. + /// Can only be set prior to calling End. /// /// number of rows returned by this traced database request. Only positive values are allowed. void SetRowsReturned(int rowsReturned); - /// - /// Adds optional information about round-trip count to database server. Must be set before end() - /// of this tracer is being called. - /// - /// count of round-trips that took place. Only positive values are allowed - void SetRoundTripCount(int roundTripCount); + /// + /// Adds optional information about round-trip count to database server. + /// Can only be set prior to calling End. + /// + /// count of round-trips that took place. Only positive values are allowed + void SetRoundTripCount(int roundTripCount); } } diff --git a/src/Api/IIncomingRemoteCallTracer.cs b/src/Api/IIncomingRemoteCallTracer.cs index da2b13b..e839da8 100644 --- a/src/Api/IIncomingRemoteCallTracer.cs +++ b/src/Api/IIncomingRemoteCallTracer.cs @@ -1,17 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api { - public interface IIncomingRemoteCallTracer : ITracer, IIncomingTaggable + /// + /// Interface for incoming remote call tracer. + /// + public interface IIncomingRemoteCallTracer : ITracer, IIncomingTaggable { /// /// Sets the name of the used remoting protocol. /// /// - void SetProtocolName(String protocolName); + void SetProtocolName(string protocolName); } } diff --git a/src/Api/IIncomingTaggable.cs b/src/Api/IIncomingTaggable.cs index dc159af..42075d8 100644 --- a/src/Api/IIncomingTaggable.cs +++ b/src/Api/IIncomingTaggable.cs @@ -1,35 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api { - /// - /// Common interface for incoming requests which include linking. - /// Not to be directly used by SDK user. - /// - public interface IIncomingTaggable + /// + /// Common interface for incoming requests which include linking. + /// Not to be referenced directly by SDK users. + /// + public interface IIncomingTaggable { - /// - /// Sets the tag using the string format. - /// - /// An application can call this function to set the incoming tag of an "incoming - /// taggable" tracer using the string representation. An "incoming taggable" - /// tracer has one tag. Calling this method more than once, will overwrite any - /// tag that was set by either {@link #setDynatraceByteTag(byte[])} or - /// {@link #setDynatraceStringTag(String)}. - /// - /// This function can not be used after the tracer was started. - /// - /// if null or an empty string, the incoming tag will be reset (cleared) - void SetDynatraceStringTag(string tag); + /// + /// Sets the tag using the string format. + /// + /// An application can call this function to set the incoming tag of an "incoming + /// taggable" tracer using the string representation. An "incoming taggable" + /// tracer has one tag. Calling this method more than once will overwrite any + /// tag that was set by either or + /// . + /// + /// This function can not be used after the tracer was started. + /// + /// if null or an empty string, the incoming tag will be reset (cleared) + void SetDynatraceStringTag(string tag); - /// - /// Same as {@link #setDynatraceStringTag(String)}, but tag is provided in binary format. - /// - /// if null or an empty string, the incoming tag will be reset (cleared). - void SetDynatraceByteTag(byte[] tag); + /// + /// Same as but tag is provided in binary format. + /// + /// if null or an empty array, the incoming tag will be reset (cleared). + void SetDynatraceByteTag(byte[] tag); } } diff --git a/src/Api/IIncomingWebRequestTracer.cs b/src/Api/IIncomingWebRequestTracer.cs deleted file mode 100644 index 88d2488..0000000 --- a/src/Api/IIncomingWebRequestTracer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Dynatrace.OneAgent.Sdk.Api -{ - public interface IIncomingWebRequestTracer : ITracer, IIncomingTaggable - { - - void SetRemoteAddress(string remoteAddress); - - void AddRequestHeader(string requestHeaderKey, string requestHeaderValue); - - - void AddParameter(string parameterKey, string parameterValue); - - void AddResponseHeader(string responseHeaderKey, string responseHeaderValue); - - - void SetResponseCode(int responseCode); - } -} diff --git a/src/Api/ILoggingCallback.cs b/src/Api/ILoggingCallback.cs new file mode 100644 index 0000000..b272503 --- /dev/null +++ b/src/Api/ILoggingCallback.cs @@ -0,0 +1,37 @@ +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace Dynatrace.OneAgent.Sdk.Api +{ + /// + /// Logging-Callback gets called only inside a OneAgentSDK API call when error/warning has occurred. + /// NB: Never call any SDK API, when inside one of this callback methods. + /// + public interface ILoggingCallback + { + /// + /// Just warning. Something is missing, but agent is working normal. + /// + /// Warning message text. Never null + void Warn(string message); + + /// + /// Something that should be done can't be done. (e. g. path couldn't be started). + /// + /// Error message text. Never null + void Error(string message); + } +} \ No newline at end of file diff --git a/src/Api/IOneAgentSdk.cs b/src/Api/IOneAgentSdk.cs index 473ce7e..6289a41 100644 --- a/src/Api/IOneAgentSdk.cs +++ b/src/Api/IOneAgentSdk.cs @@ -1,42 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api.Enums; using Dynatrace.OneAgent.Sdk.Api.Infos; namespace Dynatrace.OneAgent.Sdk.Api { + /// + /// Interface implemented by OneAgentSDK. Retrieved by OneAgentSdkFactory.CreateInstance(). For details see: + /// https://github.com/Dynatrace/OneAgent-SDK-for-dotnet#oneagentsdk-object + /// + public interface IOneAgentSdk + { + /// + /// Installs a callback that gets informed, if any SDK action has failed. For details see interface. + /// The provided callback must be thread-safe, when using this instance in multithreaded environments. + /// + /// may be null, to remove current callback. provided callback replaces any previously set callback. + void SetLoggingCallback(ILoggingCallback loggingCallback); + + #region Remote Calls (incoming and outgoing) + + /// + /// Creates a tracer for an incoming remote call. + /// + /// name of the called remote method + /// name of the remote service + /// logical deployment endpoint on the server side + /// In case of a clustered/load balanced service, the serviceEndpoint represents the common logical endpoint (e.g. registry://staging-environment/myservices/serviceA). As such a single serviceEndpoint can have many processes on many hosts that services requests for it. + /// IIncomingRemoteCallTracer instance to work with + IIncomingRemoteCallTracer TraceIncomingRemoteCall(string serviceMethod, string serviceName, string serviceEndpoint); + + /// + /// Creates a tracer for an outgoing remote call. + /// + /// name of the called remote method + /// name of the remote service + /// logical deployment endpoint on the server side In case of a clustered/load balanced service, the serviceEndpoint represents the common logical endpoint (e.g. registry://staging-environment/myservices/serviceA) where as the @channelEndpoint represents the actual communication endpoint. As such a single serviceEndpoint can have many channelEndpoints. + /// communication protocol used by remote call + /// this represents the communication endpoint for the remote service. This information allows Dynatrace to tie the database requests to a specific process or cloud service. It is optional. + /// for TCP/IP: host name/IP of the server-side (can include port) + /// for UNIX domain sockets: path of domain socket file + /// for named pipes: name of pipe + /// + /// IOutgoingRemoteCallTracer instance to work with + IOutgoingRemoteCallTracer TraceOutgoingRemoteCall(string serviceMethod, string serviceName, string serviceEndpoint, ChannelType channelType, string channelEndpoint); + + #endregion + + #region Database Calls (outgoing only) + + /// + /// Initializes a DatabaseInfo instance that is required for tracing database requests. + /// + /// name of the database + /// database vendor name (e.g. Oracle, MySQL, ...), can be a user defined name + /// If possible use a constant defined in com.dynatrace.oneagent.sdk.api.enums.DatabaseVendor + /// communication protocol used to communicate with the database. + /// this represents the communication endpoint for the database. This information allows Dynatrace to tie the database requests to a specific process or cloud service. It is optional. + /// * for TCP/IP: host name/IP of the server-side (can include port in the form of "host:port") + /// * for UNIX domain sockets: name of domain socket file + /// * for named pipes: name of pipe + /// DatabaseInfo instance to work with + IDatabaseInfo CreateDatabaseInfo(string name, string vendor, ChannelType channelType, string channelEndpoint); + + /// + /// Creates a tracer for tracing outgoing SQL database requests. + /// + /// information about database + /// database SQL statement + /// DatabaseRequestTracer to work with + IDatabaseRequestTracer TraceSQLDatabaseRequest(IDatabaseInfo databaseInfo, string statement); - /// - /// Interface implemented by OneAgentSDK. Retrieved by OneAgentSdkFactory.CreateInstance(). For details see: - /// https://github.com/Dynatrace/OneAgent-SDK#oneagentsdkobject - /// - public interface IOneAgentSdk - { - - IIncomingRemoteCallTracer TraceIncomingRemoteCall(String serviceMethod, String serviceName, String serviceEndpoint); - - /// - /// Creates a tracer for tracing outgoing SQL database requests. - /// - /// information about database - /// database SQL statement - /// DatabaseRequestTracer to work with - IDatabaseRequestTracer TraceSQLDatabaseRequest(IDatabaseInfo databaseInfo, String statement); - - /// - /// Initializes a DatabaseInfo instance that is required for tracing database requests. - /// - /// name of the database - /// database vendor name (e.g. Oracle, MySQL, ...), can be a user defined name - /// If possible use a constant defined in com.dynatrace.oneagent.sdk.api.enums.DatabaseVendor - /// communication protocol used to communicate with the database. - /// this represents the communication endpoint for the database. This information allows Dynatrace to tie the database requests to a specific process or cloud service. It is optional. - /// * for TCP/IP: host name/IP of the server-side (can include port in the form of "host:port") - /// * for UNIX domain sockets: name of domain socket file - /// * for named pipes: name of pipe - /// DatabaseInfo instance to work with - IDatabaseInfo CreateDatabaseInfo(String name, String vendor, ChannelType channelType, String channelEndpoint); - } -} \ No newline at end of file + #endregion + } +} diff --git a/src/Api/IOutgoingRemoteCallTracer.cs b/src/Api/IOutgoingRemoteCallTracer.cs index cd963b0..df5ce54 100644 --- a/src/Api/IOutgoingRemoteCallTracer.cs +++ b/src/Api/IOutgoingRemoteCallTracer.cs @@ -1,12 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api { - interface IOutgoingRemoteCallTracer : ITracer, IOutgoingTaggable + /// + /// Interface for outgoing remote call tracer. + /// + public interface IOutgoingRemoteCallTracer : ITracer, IOutgoingTaggable { - void SetProtocolName(String protocolName); + /// + /// Sets the name of the used remoting protocol. This is completely optional and just for display purposes. + /// + void SetProtocolName(string protocolName); } } diff --git a/src/Api/IOutgoingTaggable.cs b/src/Api/IOutgoingTaggable.cs index 200e7cd..912bb06 100644 --- a/src/Api/IOutgoingTaggable.cs +++ b/src/Api/IOutgoingTaggable.cs @@ -1,15 +1,39 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api { - public interface IOutgoingTaggable - { - - String GetDynatraceStringTag(); + /// + /// Common interface for outgoing requests which include linking. + /// Not to be referenced directly by SDK users. + /// + public interface IOutgoingTaggable + { + /// + /// Creates a Dynatrace tag and returns the string representation of it. + /// This tag has to be transported with the remoting protocol to the destination. + /// See on how to continue a path with provided tag on the server side. + /// + /// the tag, never null + string GetDynatraceStringTag(); + /// + /// Same as but returning the tag as binary representation. + /// + /// the tag, never null byte[] GetDynatraceByteTag(); } } \ No newline at end of file diff --git a/src/Api/ITracer.cs b/src/Api/ITracer.cs index 283a162..229f0ad 100644 --- a/src/Api/ITracer.cs +++ b/src/Api/ITracer.cs @@ -1,42 +1,57 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; using System.Threading.Tasks; namespace Dynatrace.OneAgent.Sdk.Api { - public interface ITracer + /// + /// Common interface for timing-related methods. + /// Not to be directly used by SDK user. + /// + public interface ITracer { /// /// Starts this Tracer for a synchronous call. - /// This will capture all entry fields of the Tracer and - /// start the time measurement. Some entry fields must be set, before the Tracer - /// is being started (eg. - /// IncomingWebRequestTracer#addRequestHeader(String, String)). See - /// documentation of corresponding field for details. In case no other - /// restriction is documented, fields must be set prior calling End(). + /// This will capture all entry fields of the Tracer and start the time measurement. + /// Some entry fields must be set, before the Tracer is being started. + /// See documentation of corresponding field for details. + /// In case no other restriction is documented, fields must be set prior calling End(). /// Start() might only be called once per Tracer. /// void Start(); /// - /// Same as Start() for asynchronous a call (which is typically a call with the await keyword). + /// Same as Start() for an asynchronous call (which is typically a call with the await keyword). /// - void StartAsync(); + Task StartAsync(); /// /// Sets error information for this traced operation. An application should call /// this function to notify a Tracer that the traced operations has failed (e.g. /// an Exception has been thrown). - /// error(String)} must only be called once. If a traced operation + /// Error(string) must only be called once. If a traced operation /// results in multiple errors and the application wants all of them to be /// captured, it must concatenate/combine them and then call - /// Error(String)} once before calling {@link #end()}. + /// Error(string) once before calling End(). /// /// error message(s) - void Error(String message); + void Error(string message); /// /// Ends this Tracer and stops time measurement. End() might only be called @@ -45,46 +60,46 @@ public interface ITracer void End(); - /// - /// Convenient method. - /// Traces an Action, which represents a synchronous call - /// without return value. It automatically calls Start() and End(), - /// and in case of an exception also the Error(String) method. - /// - /// An action that wraps the method call you want to trace - void Trace(Action action); + /// + /// Convenience method. + /// Traces an Action, which represents a synchronous call + /// without return value. It automatically calls Start() and End(), + /// and in case of an exception also the Error(string) method. + /// + /// An action that wraps the method call you want to trace + void Trace(Action action); - /// - /// Convenient method. - /// Traces a Func, which represents a synchronous call - /// with a return value. It automatically calls Start() and End(), - /// and in case of an exception also the Error(String) method. - /// - /// The return type of the wraped method - /// A func that wraps the method call you want to trace - /// The return value of the wraped method - T Trace(Func func); + /// + /// Convenience method. + /// Traces a Func, which represents a synchronous call + /// with a return value. It automatically calls Start() and End(), + /// and in case of an exception also the Error(string) method. + /// + /// The return type of the wrapped method + /// A func that wraps the method call you want to trace + /// The return value of the wrapped method + T Trace(Func func); - /// - /// Convenient method. - /// Traces an Func, which represents a asynchronous call - /// without return value. It automatically calls StartAsync() and End(), - /// and in case of an exception also the Error(String) method. - /// - /// A func that wraps the method call you want to trace - /// The task that you waped in the Task, which you can await on - Task Trace(Func func); + /// , which represents an asynchronous call + /// without a return value. It automatically calls StartAsync() and End(), + /// and in case of an exception also the Error(string) method. + /// ]]> + /// A func that wraps the method call you want to trace + /// The task that you wrapped in the Task, which you can await on + Task TraceAsync(Func func); - /// - /// Convenient method. - /// Traces a Func>, which represents a asynchronous call - /// with a return value. It automatically calls StartAsync() and End(), - /// and in case of an exception also the Error(String) method. - /// - /// The return type of the wraped method - /// A func that wraps the method call you want to trace - /// The task that you waped in the Task, which you can await on - Task Trace(Func> func); + /// >, which represents an asynchronous call + /// with a return value. It automatically calls StartAsync() and End(), + /// and in case of an exception also the Error(string) method. + /// ]]> + /// The return type of the wrapped method + /// A func that wraps the method call you want to trace + /// , which you can await on ]]> + Task TraceAsync(Func> func); } } diff --git a/src/Api/Infos/DatabaseInfo.cs b/src/Api/Infos/DatabaseInfo.cs index 025478a..3de41ea 100644 --- a/src/Api/Infos/DatabaseInfo.cs +++ b/src/Api/Infos/DatabaseInfo.cs @@ -1,12 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// namespace Dynatrace.OneAgent.Sdk.Api.Infos { - ///TBD: What if the user implements this and passes it to us?! - public interface IDatabaseInfo + /// + /// Type returned by + /// + public interface IDatabaseInfo { } } diff --git a/src/DummyImpl/DummyDatabaseInfo.cs b/src/DummyImpl/DummyDatabaseInfo.cs index 0a28528..7ac28f6 100644 --- a/src/DummyImpl/DummyDatabaseInfo.cs +++ b/src/DummyImpl/DummyDatabaseInfo.cs @@ -1,13 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api.Infos; namespace Dynatrace.OneAgent.Sdk.Api.DummyImpl { - internal class DummyDatabaseInfo : IDatabaseInfo + internal class DummyDatabaseInfo : IDatabaseInfo { public DummyDatabaseInfo() { diff --git a/src/DummyImpl/DummyDatabaseRequestTracer.cs b/src/DummyImpl/DummyDatabaseRequestTracer.cs index b7a83bd..7972c09 100644 --- a/src/DummyImpl/DummyDatabaseRequestTracer.cs +++ b/src/DummyImpl/DummyDatabaseRequestTracer.cs @@ -1,12 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; using System.Threading.Tasks; namespace Dynatrace.OneAgent.Sdk.Api.DummyImpl { - internal class DummyDatabaseRequestTracer : IDatabaseRequestTracer + internal class DummyDatabaseRequestTracer : IDatabaseRequestTracer { public void End() { @@ -28,12 +41,12 @@ public void Start() { } - public void StartAsync() - { - - } + public Task StartAsync() + { + return Task.FromResult(0); + } - public void Trace(Action action) + public void Trace(Action action) { action(); } @@ -43,12 +56,12 @@ public T Trace(Func func) return func(); } - public Task Trace(Func func) + public Task TraceAsync(Func func) { return func(); } - public Task Trace(Func> func) + public Task TraceAsync(Func> func) { return func(); } diff --git a/src/DummyImpl/DummyIncomingRemoteCallTracer.cs b/src/DummyImpl/DummyIncomingRemoteCallTracer.cs index e21637c..11102bd 100644 --- a/src/DummyImpl/DummyIncomingRemoteCallTracer.cs +++ b/src/DummyImpl/DummyIncomingRemoteCallTracer.cs @@ -1,12 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; using System.Threading.Tasks; namespace Dynatrace.OneAgent.Sdk.Api.DummyImpl { - internal class DummyIncomingRemoteCallTracer : IIncomingRemoteCallTracer + internal class DummyIncomingRemoteCallTracer : IIncomingRemoteCallTracer { public void End() { @@ -32,9 +45,9 @@ public void Start() { } - public void StartAsync() + public Task StartAsync() { - + return Task.FromResult(0); } public void Trace(Action action) @@ -47,12 +60,12 @@ public T Trace(Func func) return func(); } - public Task Trace(Func func) + public Task TraceAsync(Func func) { return func(); } - public Task Trace(Func> func) + public Task TraceAsync(Func> func) { return func(); } diff --git a/src/DummyImpl/DummyOutgoingRemoteCallTracer.cs b/src/DummyImpl/DummyOutgoingRemoteCallTracer.cs new file mode 100644 index 0000000..27674f7 --- /dev/null +++ b/src/DummyImpl/DummyOutgoingRemoteCallTracer.cs @@ -0,0 +1,59 @@ +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Threading.Tasks; + +namespace Dynatrace.OneAgent.Sdk.Api.DummyImpl +{ + internal class DummyOutgoingRemoteCallTracer : IOutgoingRemoteCallTracer + { + public void End() + { + } + + public void Error(string message) + { + } + + public byte[] GetDynatraceByteTag() => new byte[0]; + + public string GetDynatraceStringTag() => string.Empty; + + public void SetProtocolName(string protocolName) + { + } + + public void Start() + { + } + + public Task StartAsync() + { + return Task.FromResult(0); + } + + public void Trace(Action action) + { + } + + public T Trace(Func func) => func(); + + public Task TraceAsync(Func func) => func(); + + public Task TraceAsync(Func> func) => func(); + } +} diff --git a/src/DummyImpl/OneAgentSDKDummy.cs b/src/DummyImpl/OneAgentSDKDummy.cs index fdea85b..18a470e 100644 --- a/src/DummyImpl/OneAgentSDKDummy.cs +++ b/src/DummyImpl/OneAgentSDKDummy.cs @@ -1,32 +1,45 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api.Enums; using Dynatrace.OneAgent.Sdk.Api.Infos; namespace Dynatrace.OneAgent.Sdk.Api.DummyImpl { - internal class OneAgentSdkDummy : IOneAgentSdk - { + internal class OneAgentSdkDummy : IOneAgentSdk + { + private readonly DummyDatabaseInfo dummyDatabaseInfo = new DummyDatabaseInfo(); + private readonly DummyDatabaseRequestTracer dummyDatabaseRequestTracer = new DummyDatabaseRequestTracer(); + private readonly DummyIncomingRemoteCallTracer dummyIncomingRemoteCallTracer = new DummyIncomingRemoteCallTracer(); + private readonly DummyOutgoingRemoteCallTracer dummyOutgoingRemoteCallTracer = new DummyOutgoingRemoteCallTracer(); + + public IDatabaseInfo CreateDatabaseInfo(string name, string vendor, ChannelType channelType, string channelEndpoint) + => dummyDatabaseInfo; - private DummyDatabaseInfo dummyDatabaseInfo = new DummyDatabaseInfo(); - private DummyDatabaseRequestTracer dummyDatabaseRequestTracer = new DummyDatabaseRequestTracer(); - private DummyIncomingRemoteCallTracer dummyIncomingRemoteCallTracer = new DummyIncomingRemoteCallTracer(); + public IIncomingRemoteCallTracer TraceIncomingRemoteCall(string serviceMethod, string serviceName, string serviceEndpoint) + => dummyIncomingRemoteCallTracer; - public IDatabaseInfo CreateDatabaseInfo(string name, string vendor, ChannelType channelType, string channelEndpoint) - { - return dummyDatabaseInfo; - } + public IOutgoingRemoteCallTracer TraceOutgoingRemoteCall(string serviceMethod, string serviceName, string serviceEndpoint, ChannelType channelType, string channelEndpoint) + => dummyOutgoingRemoteCallTracer; - public IIncomingRemoteCallTracer TraceIncomingRemoteCall(string serviceMethod, string serviceName, string serviceEndpoint) - { - return dummyIncomingRemoteCallTracer; - } + public IDatabaseRequestTracer TraceSQLDatabaseRequest(IDatabaseInfo databaseInfo, string statement) + => dummyDatabaseRequestTracer; - public IDatabaseRequestTracer TraceSQLDatabaseRequest(IDatabaseInfo databaseInfo, string statement) - { - return dummyDatabaseRequestTracer; - } - } + public void SetLoggingCallback(ILoggingCallback loggingCallback) + { + } + } } \ No newline at end of file diff --git a/src/Dynatrace.OneAgent.Sdk.csproj b/src/Dynatrace.OneAgent.Sdk.csproj index 835a85a..f0a6af1 100644 --- a/src/Dynatrace.OneAgent.Sdk.csproj +++ b/src/Dynatrace.OneAgent.Sdk.csproj @@ -2,9 +2,29 @@ netstandard1.0 - 1.0.0-alpha + 1.1.0-alpha1 + Dynatrace + Dynatrace OneAgent SDK for .NET + This SDK allows Dynatrace customers to instrument .NET applications. This is useful to enhance the visibility for proprietary frameworks or custom frameworks not directly supported by Dynatrace OneAgent out-of-the-box. + +This SDK is currently in EAP and still work in progress. + +Requires Dynatrace OneAgent version 1.157 or newer installed. + +For further information (requirements, features, release notes) and samples see our readme on Github: +https://github.com/Dynatrace/OneAgent-SDK-for-dotnet + Copyright 2018 Dynatrace LLC; Licensed under the Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + https://github.com/Dynatrace/OneAgent-SDK-for-dotnet + https://assets.dynatrace.com/global/resources/Signet_Logo_RGB_CP_512x512px.png + https://github.com/Dynatrace/OneAgent-SDK-for-dotnet + Git true - keypairAgent.snk + Dynatrace.OneAgent.Sdk.snk + + + + true diff --git a/src/OneAgentSDKFactory.cs b/src/OneAgentSDKFactory.cs index 0dadfdc..a2f63a6 100644 --- a/src/OneAgentSDKFactory.cs +++ b/src/OneAgentSDKFactory.cs @@ -1,12 +1,27 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// Copyright 2018 Dynatrace LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + using Dynatrace.OneAgent.Sdk.Api.DummyImpl; namespace Dynatrace.OneAgent.Sdk.Api { - public class OneAgentSdkFactory + /// + /// Factory for retrieving instances of + /// + public class OneAgentSdkFactory { ///