Skip to content
This repository has been archived by the owner on Jul 5, 2020. It is now read-only.

Support W3C distributed tracing standard #945

Merged
merged 28 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Version 2.8.0-beta1
- [Adds opt-in support for W3C distributed tracing standard](https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/945)
- Update Base SDK to version 2.8.0-beta1

## Version 2.7.2
Expand Down
3 changes: 3 additions & 0 deletions Src/Common/Common.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<Compile Include="$(MSBuildThisFileDirectory)RequestResponseHeaders.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SdkVersionUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StringUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)W3C\W3CActivityExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)W3C\W3CConstants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)W3C\W3COperationCorrelationTelemetryInitializer.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'netstandard1.6' ">
<Compile Include="$(MSBuildThisFileDirectory)WebHeaderCollectionExtensions.cs" />
Expand Down
34 changes: 32 additions & 2 deletions Src/Common/InjectionGuardConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,46 @@
/// These max limits are intentionally exaggerated to allow for unexpected responses, while still guarding against unreasonably large responses.
/// Example: While a 32 character response may be expected, 50 characters may be permitted while a 10,000 character response would be unreasonable and malicious.
/// </summary>
public static class InjectionGuardConstants
#if DEPENDENCY_COLLECTOR
public
#else
internal
#endif
static class InjectionGuardConstants
{
/// <summary>
/// Max length of AppId allowed in response from Breeze.
/// </summary>
public const int AppIdMaxLengeth = 50;
public const int AppIdMaxLength = 50;

/// <summary>
/// Max length of incoming Request Header value allowed.
/// </summary>
public const int RequestHeaderMaxLength = 1024;

/// <summary>
/// Max length of context header key.
/// </summary>
public const int ContextHeaderKeyMaxLength = 50;

/// <summary>
/// Max length of context header value.
/// </summary>
public const int ContextHeaderValueMaxLength = 1024;

/// <summary>
/// Max length of traceparent header value.
/// </summary>
public const int TraceParentHeaderMaxLength = 55;

/// <summary>
/// Max length of tracestate header value string.
/// </summary>
public const int TraceStateHeaderMaxLength = 512;

/// <summary>
/// Max number of key value pairs in the tracestate header.
/// </summary>
public const int TraceStateMaxPairs = 32;
}
}
69 changes: 64 additions & 5 deletions Src/Common/StringUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
using System;
using System.Diagnostics;
using System.Globalization;
using Microsoft.ApplicationInsights.W3C;

/// <summary>
/// Generic functions to perform common operations on a string.
/// </summary>
public static class StringUtilities
#if DEPENDENCY_COLLECTOR
public
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like hiding this class from public surface. What's the reason to keep it public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this class is used by AspNetCore SDK and should be visible to it. There are two alternatives:

  • copy paste (as it is done now and i'm getting read of it by this PR)
  • move common code to based SDK. I'm not fond of it because most of W3C code will go away from AI SDK eventually and I'd prefer to keep it all in one place. We can move other StringUtilities common methods in different PR

#else
internal
#endif
static class StringUtilities
{
private static readonly uint[] Lookup32 = CreateLookup32();

Expand Down Expand Up @@ -35,11 +41,64 @@ public static string EnforceMaxLength(string input, int maxLength)
/// <returns>Random 16 bytes array encoded as hex string</returns>
public static string GenerateTraceId()
{
// See https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa/24343727#24343727
var bytes = Guid.NewGuid().ToByteArray();
return GenerateId(Guid.NewGuid().ToByteArray(), 0, 16);
}

/// <summary>
/// Generates random span Id as per W3C Distributed tracing specification.
/// https://github.com/w3c/distributed-tracing/blob/master/trace_context/HTTP_HEADER_FORMAT.md#span-id
/// </summary>
/// <returns>Random 8 bytes array encoded as hex string</returns>
public static string GenerateSpanId()
{
return GenerateId(Guid.NewGuid().ToByteArray(), 0, 8);
}

var result = new char[32];
for (int i = 0; i < 16; i++)
/// <summary>
/// Formats trace Id and span Id into valid Request-Id: |trace.span.
/// </summary>
/// <param name="traceId">Trace Id.</param>
/// <param name="spanId">Span id.</param>
/// <returns>valid Request-Id.</returns>
public static string FormatRequestId(string traceId, string spanId)
{
return String.Concat("|", traceId, ".", spanId, ".");
}

/// <summary>
/// Gets root id (string between '|' and the first dot) from the hierarchical Id.
/// </summary>
/// <param name="hierarchicalId">Id to extract root from.</param>
/// <returns>Root operation id.</returns>
internal static string GetRootId(string hierarchicalId)
{
// Returns the root Id from the '|' to the first '.' if any.
int rootEnd = hierarchicalId.IndexOf('.');
if (rootEnd < 0)
{
rootEnd = hierarchicalId.Length;
}

int rootStart = hierarchicalId[0] == '|' ? 1 : 0;
return hierarchicalId.Substring(rootStart, rootEnd - rootStart);
}

#pragma warning disable 612, 618
internal static string FormatAzureTracestate(string appId)
{
return String.Concat(W3CConstants.AzureTracestateNamespace, "=", appId);
}
#pragma warning restore 612, 618

/// <summary>
/// Converts byte array to hex lower case string.
/// </summary>
/// <returns>Array encoded as hex string</returns>
private static string GenerateId(byte[] bytes, int start, int length)
{
// See https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa/24343727#24343727
var result = new char[length * 2];
for (int i = start; i < start + length; i++)
{
var val = Lookup32[bytes[i]];
result[2 * i] = (char)val;
Expand Down
Loading