Skip to content

Commit

Permalink
Core: add AddBetterHttpIntrumentation(..) extension methods for OpenT…
Browse files Browse the repository at this point in the history
…elemetry Tracing and Metrics

- enable the default trace and metrics sources needed to monitor HTTP requests
  • Loading branch information
KrzysFR committed Aug 1, 2024
1 parent 0290664 commit 8a36f26
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Doxense.Networking.Http/Doxense.Networking.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputType>Library</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<CopyLocalLocFileAssemblies>true</CopyLocalLocFileAssemblies>
<LangVersion>11.0</LangVersion>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,4 +510,5 @@ private void Dispose(bool disposing)
#endregion

}

}
23 changes: 11 additions & 12 deletions Doxense.Networking.Http/Networking/Http/BetterHttpClientContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ namespace Doxense.Networking.Http
public class BetterHttpClientContext
{

private static readonly ActivitySource ActivitySource = new("Doxense.Networking.Http");

/// <summary>Instance of the <see cref="BetterHttpClient">client</see> executing this request</summary>
public required BetterHttpClient Client { get; init; }
Expand Down Expand Up @@ -164,14 +163,14 @@ public bool IsLikelyJson()
public async Task<JsonValue> ReadAsJsonAsync(CrystalJsonSettings? settings = null)
{
this.Cancellation.ThrowIfCancellationRequested();
using var activity = ActivitySource.StartActivity("JSON Parse");
using var activity = BetterHttpInstrumentation.ActivitySource.StartActivity("JSON Parse");

try
{
//BUGBUG: PERF: tant qu'on n'a pas de read async json, on est obligé de buffer dans un MemoryStream!!
using (var ms = DefaultPool.GetStream())
{
await this.CopyToAsync(ms);
await this.CopyToAsync(ms).ConfigureAwait(false);
return CrystalJson.Parse(ms.ToSlice(), settings);
}
}
Expand All @@ -186,14 +185,14 @@ public async Task<JsonValue> ReadAsJsonAsync(CrystalJsonSettings? settings = nul
public async Task<JsonObject?> ReadAsJsonObjectAsync(CrystalJsonSettings? settings = null)
{
this.Cancellation.ThrowIfCancellationRequested();
using var activity = ActivitySource.StartActivity("JSON Parse");
using var activity = BetterHttpInstrumentation.ActivitySource.StartActivity("JSON Parse");

try
{
//BUGBUG: PERF: tant qu'on n'a pas de read async json, on est obligé de buffer dans un MemoryStream!!
using (var ms = DefaultPool.GetStream())
{
await CopyToAsync(ms);
await CopyToAsync(ms).ConfigureAwait(false);
activity?.SetTag("json.length", ms.Length);
return CrystalJson.Parse(ms.ToSlice(), settings).AsObjectOrDefault();
}
Expand All @@ -209,14 +208,14 @@ public async Task<JsonValue> ReadAsJsonAsync(CrystalJsonSettings? settings = nul
public async Task<JsonArray?> ReadAsJsonArrayAsync(CrystalJsonSettings? settings = null)
{
this.Cancellation.ThrowIfCancellationRequested();
using var activity = ActivitySource.StartActivity("JSON Parse");
using var activity = BetterHttpInstrumentation.ActivitySource.StartActivity("JSON Parse");

try
{
//BUGBUG: PERF: tant qu'on n'a pas de read async json, on est obligé de buffer dans un MemoryStream!!
using (var ms = DefaultPool.GetStream())
{
await CopyToAsync(ms);
await CopyToAsync(ms).ConfigureAwait(false);
return CrystalJson.Parse(ms.ToSlice(), settings).AsArrayOrDefault();
}
}
Expand All @@ -231,14 +230,14 @@ public async Task<JsonValue> ReadAsJsonAsync(CrystalJsonSettings? settings = nul
public async Task<TResult?> ReadAsJsonAsync<TResult>(CrystalJsonSettings? settings = null, ICrystalJsonTypeResolver? resolver = null)
{
this.Cancellation.ThrowIfCancellationRequested();
using var activity = ActivitySource.StartActivity("JSON Parse");
using var activity = BetterHttpInstrumentation.ActivitySource.StartActivity("JSON Parse");

try
{
//BUGBUG: PERF: tant qu'on n'a pas de read async json, on est obligé de buffer dans un MemoryStream!!
using (var ms = DefaultPool.GetStream())
{
await CopyToAsync(ms);
await CopyToAsync(ms).ConfigureAwait(false);
return CrystalJson.Deserialize<TResult?>(ms.ToSlice(), default, settings, resolver);
}
}
Expand Down Expand Up @@ -268,14 +267,14 @@ public bool IsLikelyXml()
public async Task<XDocument?> ReadAsXmlAsync(LoadOptions options = LoadOptions.None)
{
this.Cancellation.ThrowIfCancellationRequested();
using var activity = ActivitySource.StartActivity("XML Parse");
using var activity = BetterHttpInstrumentation.ActivitySource.StartActivity("XML Parse");

try
{
var stream = await this.Response.Content.ReadAsStreamAsync(this.Cancellation);
var stream = await this.Response.Content.ReadAsStreamAsync(this.Cancellation).ConfigureAwait(false);
//note: do NOT dispose this stream here!

return await XDocument.LoadAsync(stream, options, this.Cancellation);
return await XDocument.LoadAsync(stream, options, this.Cancellation).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#region Copyright (c) 2023-2024 SnowBank SAS, (c) 2005-2023 Doxense SAS
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of SnowBank nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL SNOWBANK SAS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

namespace Doxense.Networking.Http
{
using System.Diagnostics;

internal static class BetterHttpInstrumentation
{

public const string ActivityName = "Doxense.Networking.Http";
public const string ActivityVersion = "0.1.0"; //TODO: what version should we use?

public static readonly ActivitySource ActivitySource = new(ActivityName, ActivityVersion);

//TODO: add Meters here!
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#region Copyright (c) 2023-2024 SnowBank SAS, (c) 2005-2023 Doxense SAS
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of SnowBank nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL SNOWBANK SAS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

namespace OpenTelemetry.Trace
{
using Doxense.Networking.Http;
using OpenTelemetry.Metrics;

public static class BetterHttpOpenTelemetryExtensions
{

/// <summary>Enable instrumentation for all "core" features of the SDK</summary>
public static TracerProviderBuilder AddBetterHttpIntrumentation(this TracerProviderBuilder builder)
{
builder.AddSource([
BetterHttpInstrumentation.ActivityName,
"SnowBank.Sdk.Serialization.Json",
"Doxense.Serialization.Json", //LEGACY: will be removed at some point
]);
return builder;
}

/// <summary>Enable instrumentation for all "core" features of the SDK</summary>
public static MeterProviderBuilder AddBetterHttpInstrumentation(this MeterProviderBuilder builder)
{
//TODO: add counters!
return builder;
}

}

}

0 comments on commit 8a36f26

Please sign in to comment.