Public APIedit

The public API of the Elastic APM .NET agent lets you customize and manually create spans and transactions, as well as track errors.

Tracer APIedit

The tracer gives you access to the currently active transaction and it enables you to manually start a transaction.

You can access the API by using the static property on the Agent: Elastic.Apm.Agent.Tracer.

ITransaction StartTransaction(string name, string type)edit

Use this method to create a custom transaction.

Note that in the case of auto-instrumentation, the agent will automatically do this for you. For example, if you have incoming HTTP calls in an ASP.NET Core application, the agent automatically starts a transaction. In these instances, this method is not needed.

It’s important to call void End() when the transaction has ended. A best practice is to use the transaction in a try-catch-finally block or to use the CaptureTransaction method.

Example:

var transaction = Elastic.Apm.Agent
        .Tracer.StartTransaction("MyTransaction", ApiConstants.TypeRequest);
try
{
    //application code that is captured as a transaction
}
catch (Exception e)
{
    transaction.CaptureException(e);
    throw;
}
finally
{
    transaction.End();
}

ITransaction CurrentTransactionedit

Returns the currently active transaction. See the Transaction API to customize the current transaction.

If there is no current transaction, this method will return null.

var transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;

ISpan CurrentSpanedit

Returns the currently active span. See the Span API to customize the current span.

If there is no current span, this method will return null.

var span = Elastic.Apm.Agent.Tracer.CurrentSpan;

CaptureTransactionedit

This is a convenient method which starts and ends a transaction and captures unhandled exceptions. It has 3 parameters:

  • name: The name of the transaction
  • type The type of the transaction
  • One of the following types which references the code that you want to capture as a transaction:

    • Action
    • Action<ITransaction>
    • Func<T>
    • Func<ITransaction,T>
    • Func<Task>
    • Func<ITransaction,Task>
    • Func<Task<T>>
    • Func<ITransaction,Task<T>>

The following code is the equivalent of the previous example with the convenient API. It automatically starts and ends the transaction and reports unhandled exceptions. The t parameter gives you access to the ITransaction instance which represents the transaction that you just created.

Elastic.Apm.Agent.Tracer
        .CaptureTransaction("TestTransaction", ApiConstants.TypeRequest, (t) =>
{
   //application code that is captured as a transaction
});

This API also supports async methods with the Func<Task> overloads.

Note

The duration of the transaction will be the timespan between the first and the last line of the async lambda expression.

Example:

await Elastic.Apm.Agent.Tracer
        .CaptureTransaction("TestTransaction", "TestType", async () =>
{
    //application code that is captured as a transaction
    await Task.Delay(500); //sample async code
});
Note

Return value of CaptureTransaction method overloads that accept Task (or Task<T>) is the same Task (or Task<T>) instance as the one passed as the argument so if your application should continue only after the task completes you have to call CaptureTransaction with await keyword.

Manually propagating distributed tracing contextedit

Agent automatically propagates distributed tracing context for the supported technologies (see Networking client-side technologies). If your application communicates over a protocol that is not supported by the agent you can manually propagate distributed tracing context from the caller to the callee side using Public Agent API.

First you serialize distributed tracing context on the caller side:

string outgoingDistributedTracingData = Agent.Tracer.CurrentTransaction
                     .OutgoingDistributedTracingData.SerializeToString();

Then you transfer the resulted string to the callee side and you continue the trace by passing deserialized distributed tracing context to any of ITransaction StartTransaction(string name, string type) or CaptureTransaction APIs - all of these APIs have an optional DistributedTracingData parameter. For example:

var transaction2 = Agent.Tracer.StartTransaction("Transaction2", "TestTransaction",
     DistributedTracingData.TryDeserializeFromString(serializedDistributedTracingData));

Transaction APIedit

A transaction describes an event captured by an Elastic APM agent monitoring a service. Transactions help combine multiple Spans into logical groups, and they are the first Span of a service. More information on Transactions and Spans is available in the APM data model documentation.

See ITransaction CurrentTransaction on how to get a reference of the current transaction.

Note

Calling any of the transaction’s methods after void End() has been called is illegal. You may only interact with a transaction when you have control over its lifecycle.

ISpan StartSpan(string name, string type, string subType = null, string action = null)edit

Start and return a new custom span as a child of the given transaction.

It is important to call void End() when the span has ended or to use the CaptureSpan method. A best practice is to use the span in a try-catch-finally block.

Example:

ISpan span = transaction.StartSpan("Select FROM customer",
     ApiConstants.TypeDb, ApiConstants.SubtypeMssql, ApiConstants.ActionQuery);
try
{
    //execute db query
}
catch(Exception e)
{
    span.CaptureException(e);
    throw;
}
finally
{
    span.End();
}

Dictionary<string,string> Labelsedit

A flat mapping of user-defined labels with string values.

Tip

Before using custom labels, ensure you understand the different types of metadata that are available.

Warning

Avoid defining too many user-specified labels. Defining too many unique fields in an index is a condition that can lead to a mapping explosion.

Ageny.Tracer
 .CaptureTransaction(TransactionName, TransactionType,
    transaction =>
    {
        transaction.Labels["foo"] = "bar";
        //application code that is captured as a transaction
    });
  • key: The label key
  • value: The label value

void End()edit

Ends the transaction and schedules it to be reported to the APM Server.

It is illegal to call any methods on a span instance which has already ended. This also includes this method and ISpan StartSpan(string name, string type, string subType = null, string action = null).

Example:

transaction.End();
Note

If you use the CaptureTransaction method you must not call void End().

void CaptureException(Exception e)edit

Captures an exception and reports it to the APM server.

void CaptureError(string message, string culprit, StackFrame[] frames)edit

Captures a custom error and reports it to the APM server.

This method is typically used when you want to report an error, but you don’t have an Exception instance.

CaptureSpanedit

This is a convenient method which starts and ends a span on the given transaction and captures unhandled exceptions. It has the same overloads as the CaptureTransaction method. It has 5 parameters:

  • name: The name of the span
  • type The type of the span
  • One of the following types which references the code that you want to capture as a transaction:

    • Action
    • Action<ITransaction>
    • Func<T>
    • Func<ITransaction,T>
    • Func<Task>
    • Func<ITransaction,Task>
    • Func<Task<T>>
    • Func<ITransaction,Task<T>>
  • supType (optional): The subtype of the span
  • action (optional): The action of the span

The following code is the equivalent of the previous example from the ISpan StartSpan(string name, string type, string subType = null, string action = null) section with the convenient API. It automatically starts and ends the span and reports unhandled exceptions. The s parameter gives you access to the ISpan instance which represents the span that you just created.

ITransaction transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;

transaction.CaptureSpan("SampleSpan", ApiConstants.TypeDb, (s) =>
{
    //execute db query
}, ApiConstants.SubtypeMssql, ApiConstants.ActionQuery);

Similar to the CaptureTransaction API, this method also supports async methods with the Func<Task> overloads.

Note

The duration of the span will be the timespan between the first and the last line of the async lambda expression.

This example shows you how to track an async code block that returns a result (Task<T>) as a span:

ITransaction transaction = Elastic.Apm.Agent.Tracer.CurrentTransaction;
var asyncResult = await transaction.CaptureSpan("Select FROM customer", ApiConstants.TypeDb, async(s) =>
{
    //application code that is captured as a span
    await Task.Delay(500); //sample async code
    return 42;
});
Note

Return value of CaptureSpan method overloads that accept Task (or Task<T>) is the same Task (or Task<T>) instance as the one passed as the argument so if your application should continue only after the task completes you have to call CaptureSpan with await keyword.

Note

Code samples above use Elastic.Apm.Agent.Tracer.CurrentTransaction. In production code you should make sure the CurrentTransaction is not null.

Contextedit

You can attach additional context to manually captured transactions.

If you use a web framework for which agent doesn’t capture transactions automatically (see Web Frameworks), you can add context related to the captured transaction by setting various properties of transaction’s Context property. For example:

Agent.Tracer.CaptureTransaction("MyCustomTransaction",ApiConstants.TypeRequest, (transaction) =>
{
  transaction.Context.Request = new Request(myRequestMethod, myRequestUri);

  // ... code executing the request

  transaction.Context.Response =
     new Response { StatusCode = myStatusCode, Finished = wasFinished };
});

Span APIedit

A span contains information about a specific code path, executed as part of a transaction.

If for example a database query happens within a recorded transaction, a span representing this database query may be created. In such a case, the name of the span will contain information about the query itself, and the type will hold information about the database type.

Dictionary<string,string> Labelsedit

Similar to Dictionary<string,string> Labels on the Transaction API: A flat mapping of user-defined labels with string values.

Tip

Before using custom labels, ensure you understand the different types of metadata that are available.

Warning

Avoid defining too many user-specified labels. Defining too many unique fields in an index is a condition that can lead to a mapping explosion.

transaction.CaptureSpan(SpanName, SpanType,
span =>
    {
        span.Labels["foo"] = "bar";
        //application code that is captured as a span
    });

void CaptureException(Exception e)edit

Captures an exception and reports it to the APM server.

void CaptureError(string message, string culprit, StackFrame[] frames)edit

Captures a custom error and reports it to the APM server.

This method is typically used when you want to report an error, but you don’t have an Exception instance.

void End()edit

Ends the span and schedules it to be reported to the APM Server.

It is illegal to call any methods on a span instance which has already ended.

Contextedit

You can attach additional context to manually captured spans.

If you use a database library for which agent doesn’t capture spans automatically (see Data Access Technologies), you can add context related to the captured database operation by setting span’s Context.Db property. For example:

Agent.Tracer.CurrentTransaction.CaptureSpan("MyDbWrite", ApiConstants.TypeDb, (span) =>
{
    span.Context.Db = new Database
        { Statement = myDbStatement, Type = myDbType, Instance = myDbInstance };

    // ... code executing the database operation
});

If you use an HTTP library for which agent doesn’t capture spans automatically (see Networking client-side technologies), you can add context related to the captured HTTP operation by setting span’s Context.Http property. For example:

Agent.Tracer.CurrentTransaction.CaptureSpan("MyHttpOperation", ApiConstants.TypeExternal, (span) =>
{
    span.Context.Http = new Http
        { Url = myUrl, Method = myMethod };

    // ... code executing the HTTP operation

    span.Context.Http.StatusCode = myStatusCode;
});