Skip to content

Commit 72011ec

Browse files
author
Emanuele Palazzetti
authored
Merge pull request #31 from bmermet/updatedoc
Update the documentation before the 0.1.2 release
2 parents 45fea77 + 6b7573b commit 72011ec

File tree

1 file changed

+79
-117
lines changed

1 file changed

+79
-117
lines changed

README.md

Lines changed: 79 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ This repository contains what you need to trace C# applications. Some quick note
99
- **Datadog C# APM is currently in Alpha**
1010
- It supports .Net Framework version above 4.5 and .Net Core 2.0.
1111
- It does not support out of process propagation.
12-
- It does not provide automatic framework instrumentation, all instrumentation is [manual](#manual-instrumentation).
1312
- Multiple AppDomains are not supported.
14-
- Our tracer is based on the current OpenTracing standard, however we do not yet support the following features: `FollowsFrom` references, `Baggage` or `Log`.
1513

1614
## The Components
1715

@@ -56,6 +54,26 @@ And check that the status is "running".
5654

5755
The logs are available at the path you configured in `trace.config` `log_file` above.
5856

57+
### Automatic Instrumentation
58+
59+
#### ASP.NET Core
60+
61+
To instrument you ASP.NET Core application install the
62+
`Datadog.Trace.AspNetCore` NuGet package and the following line to your
63+
`ConfigureServices` method:
64+
65+
```csharp
66+
public void ConfigureServices(IServiceCollection services)
67+
{
68+
services
69+
.AddDatadogTrace()
70+
}
71+
```
72+
73+
Once your application is configured this way all the requests to your
74+
application will be traced and the active span will automatically be set to the
75+
currently executing request.
76+
5977
### Manual Instrumentation
6078

6179
#### Introduction
@@ -64,167 +82,111 @@ Before instrumenting your application, have a look at the [Datadog APM Terminolo
6482

6583
#### Setup
6684

67-
In order to instrument you code you need to add the `Datadog.Trace` NuGet package to your project.
85+
In order to instrument your code you need to add the `Datadog.Trace` NuGet
86+
package to your project.
87+
88+
Your tracing adventure starts with the `Tracer` class that will be used to
89+
instrument your code and should be accessed exclusively through the
90+
`Tracer.Instance` singleton. `Trace.Instance` is statically initialized with a
91+
`Tracer` created with the default settings but you may instantiate a new one
92+
with customized values with the `Tracer.Create` method.
6893

69-
Your tracing adventure starts with the `ITracer` object, you should typically instantiate only one `ITracer` for the lifetime of your app and use it in all places of your code where you want to add tracing. Instantiating the `ITracer` is done with the `TracerFactory.GetTracer` method.
94+
`Tracer.Create` takes a number of optional parameters that can be used to
95+
customize the returned `Tracer`:
7096

71-
To get a tracer with default parameters (i.e. the agent endpoint set to `http://localhost:8126`, and the default service name set to the name of the AppDomain):
97+
- agentEndpoint: the agent endpoint where the traces will be sent (default is http://localhost:8126)
98+
- defaultServiceName: default name of the service (default is the name of the executing assembly)
99+
- isDebugEnabled: turns on all debug logging, this may have an impact on application performance (default is false)
100+
101+
For example to set a custom service name:
72102

73103
```csharp
74-
ITracer tracer = TracerFactory.GetTracer();
104+
Tracer.Instance = Tracer.Create(defaultServiceName: "YourServiceName")
75105
```
76106

77-
Customize your tracer object by adding optional parameters to the `TracerFactory.GetTracer` call:
107+
#### In process propagation
108+
109+
We want to keep track of the dependencies between spans created inside a
110+
process. This is done automatically by the tracer when using the `StartActive`
111+
method that returns a Scope representing the scope in which the created Span is
112+
considered active. All Spans created without `ignoreActiveScope = true` are
113+
automatically parented to the current active Span and become themselves active
114+
(unless the `StartSpan` method is used).
78115

79-
By default the service name is set to the name of the AppDomain, choose a custom name with the defaultServiceName parameter:
116+
If not created with `finishOnClose = false` closing a Scope will also close the
117+
Span it is enclosing.
118+
119+
Examples:
80120

81121
```csharp
82-
ITracer tracer = TracerFactory.GetTracer(defaultServiceName: "YourServiceName")
122+
// The second span will be a child of the first one.
123+
using (Scope scope = Tracer.Instance.StartActive("Parent")){
124+
using(Scope scope = Tracer.Instance.StartActive("Child")){
125+
}
126+
}
83127
```
84128

85-
By default, the trace endpoint is set to http://localhost:8126, send traces to a different endpoint with the agentEndpoint parameter:
86-
87129
```csharp
88-
ITracer tracer = TracerFactory.GetTracer(agentEndpoint: new Url("http://myendpoint:port"));
130+
// Since it is created with the StartSpan method the first span is not made
131+
// active and the second span will not be parented to it.
132+
using (Span span = Tracer.Instance.StartSpan("Span1")){
133+
using(Scope scope = Tracer.Instance.StartActive("Span2")){
134+
}
135+
}
89136
```
90137

91-
#### Examples
138+
#### Code instrumentation
92139

93-
Use the shared `ITracer` object you created to create spans, instrument any section of your code, and get detailed metrics on it.
140+
Use the shared `Tracer` object you created to create spans, instrument any
141+
section of your code, and get detailed metrics on it.
94142

95-
Set the ServiceName to recognize which service this trace belongs to; if you don't, the parent span's service name or in case of a root span the defaultServiceName stated above is used.
143+
Set the ServiceName to recognize which service this trace belongs to; if you
144+
don't, the parent span's service name or in case of a root span the
145+
defaultServiceName stated above is used.
96146

97147
Set the ResourceName to scope this trace to a specific endpoint or SQL Query; For instance:
98148
- "GET /users/:id"
99149
- "SELECT * FROM ..."
100150
if you don't the OperationName will be used.
101151

102-
A minimal examples is:
152+
A minimal example is:
103153

104154
```csharp
105-
using (ISpan span = tracer.BuildSpan("OperationName").WithTag(DDTags.ServiceName, "ServiceName").Start())
155+
using (Scope scope = Tracer.Instance.StartActive("OperationName", serviceName: "ServiceName"))
106156
{
107-
span.SetTag(DDTags.ResourceName, "ResourceName");
157+
scope.Span.ResourceName = "ResourceName";
108158

109159
// Instrumented code
110160
Thread.Sleep(1000);
111161
}
112162
```
113163

114-
You may also choose, not to use the `using` construct and close the `ISpan` object explictly:
164+
You may also choose, not to use the `using` construct and close the `Scope` object explictly:
115165

116166
```csharp
117-
ISpan span = tracer.BuildSpan("OperationName").WithTag(DDTags.ServiceName, "ServiceName").Start();
118-
span.SetTag(DDTags.ResourceName, "ResourceName");
167+
Scope scope = Tracer.Instance.StartActive("OperationName", serviceName: "ServiceName");
168+
scope.Span = "ResourceName";
119169

120170
// Instrumented code
121171
Thread.Sleep(1000);
122172

123173

124-
// Finish sets the span duration and sends it to the agent (if you don't call finish the data will never be sent to Datadog)
125-
span.Finish();
126-
```
127-
128-
You may add custom tags by calling `ISpan.SetTag`:
129-
130-
```csharp
131-
ISpan span = tracer.BuildSpan("SqlQuery").Start();
132-
span.SetTag("db.rows", 10);
174+
// Close closes the underlying span, this sets its duration and sends it to the agent (if you don't call Close the data will never be sent to Datadog)
175+
scope.Close();
133176
```
134177

135-
You should not have to explicitly declare parent/children relationship between your spans, but to override the default behavior - a new span is considered a child of the innermost open span in its logical context- use:
178+
You may add custom tags by calling `Span.SetTag`:
136179

137180
```csharp
138-
ISpan parent = tracer.BuildSpan("Parent").Start();
139-
ISpan child = tracer.BuildSpan("Child").AsChildOf(parent).Start();
181+
Scope scope = Tracer.Instance.StartActive("SqlQuery");
182+
scope.Span.SetTag("db.rows", 10);
140183
```
141184

142-
#### Cross-process tracing
143-
144-
Cross-process tracing is supported by propagating context through HTTP headers. This is done with the `ITracer.Inject` and `ITracer.Extract` methods as documented in the [opentracing documentation](http://opentracing.io/documentation/pages/api/cross-process-tracing.html)
145-
146-
##### Injection
147-
148-
Example code to send a HTTP request with the right headers:
185+
You should not have to explicitly declare parent/children relationship between your spans, but to override the default behavior - a new span is considered a child of the active Span - use:
149186

150187
```csharp
151-
using (var span = tracer.BuildSpan("Operation").Start())
152-
{
153-
var client = new HttpClient();
154-
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com");
155-
var carrier = new HttpHeadersCarrier(_request.Headers);
156-
tracer.Inject(span.Context, Formats.HttpHeaders, carrier);
157-
await client.SendAsync(request);
158-
}
159-
```
160-
161-
##### Extraction
162-
163-
In order to extract context from a http request, you need to write a wrapper
164-
around the header container used by your web framework to make it implement the
165-
`ITextMap` interface.
166-
167-
For example such a wrapper for the `IHeaderDictionary` used by Asp.Net Core could be:
168-
169-
```csharp
170-
using System.Collections.Generic;
171-
using Microsoft.AspNetCore.Http;
172-
using OpenTracing.Propagation;
173-
174-
public class AspNetHeadersTextMap : ITextMap
175-
{
176-
private readonly IHeaderDictionary _headers;
177-
178-
public AspNetHeadersTextMap(IHeaderDictionary headers)
179-
{
180-
_headers = headers;
181-
}
182-
183-
public string Get(string key)
184-
{
185-
return _headers[key];
186-
}
187-
188-
public IEnumerable<KeyValuePair<string, string>> GetEntries()
189-
{
190-
return (IEnumerable<KeyValuePair<string, string>>)_headers;
191-
}
192-
193-
public void Set(string key, string value)
194-
{
195-
_headers[key] = value;
196-
}
197-
}
198-
```
199-
200-
You can then leverage the extract method to extract the cross-process
201-
correlation context from a request's headers:
202-
203-
```csharp
204-
var tracer = TracerFactory.GetTracer();
205-
var headersTextMap = new AspNetHeadersTextMap(HttpContext.Request.Headers);
206-
var spanContext = tracer.Extract(Formats.HttpHeaders, headersTextMap);
207-
using (var span = tracer.BuildSpan("Operation").AsChildOf(spanContext).Start())
208-
{
209-
// Your instrumented code
210-
}
211-
```
212-
213-
#### Advanced Usage
214-
215-
When creating a tracer, add some metadata to your services to customize how they will appear in your Datadog application:
216-
217-
```csharp
218-
var serviceInfoList = new List<ServiceInfo>
219-
{
220-
new ServiceInfo
221-
{
222-
App = "MyAppName",
223-
AppType = "web",
224-
ServiceName = "MyServiceName"
225-
}
226-
};
227-
ITracer tracer = TracerFactory.GetTracer(serviceInfoList: serviceInfoList);
188+
Span parent = tracer.StartSpan("Parent");
189+
Span child = tracer.StartSpan("Child", childOf: parent.Context);
228190
```
229191

230192
## Development

0 commit comments

Comments
 (0)