Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ContinuousProfiling] Move logic to main project #3539

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</ItemGroup>
<!-- Versions from OpenTelemetry.AutoInstrumentation.csproj -->
<ItemGroup>
<PackageVersion Include="Grpc.Net.Client" Version="2.52.0" />
<PackageVersion Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="1.4.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.HttpListener" Version="1.9.0-beta.2" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.9.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,22 @@ public static class Sdk
/// </summary>
public const string Propagators = "OTEL_PROPAGATORS";
}

#if NET6_0_OR_GREATER
/// <summary>
/// Configuration keys for continuous profiler.
/// </summary>
public static class ContinuousProfiler
{
/// <summary>
/// Configuration key for enabling thread sampling.
/// </summary>
public const string ThreadSamplingEnabled = "OTLP_DOTNET_AUTO_CONTINUOUS_PROFILER_THREAD_SAMPLING_ENABLED";

/// <summary>
/// Configuration key for enabling allocation sampling.
/// </summary>
public const string AllocationSamplingEnabled = "OTLP_DOTNET_AUTO_CONTINUOUS_PROFILER_ALLOCATION_SAMPLING_ENABLED";
}
#endif
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#if NET6_0_OR_GREATER

namespace OpenTelemetry.AutoInstrumentation.Configurations;

internal class ContinuousProfilerSettings : Settings
{
/// <summary>
/// Gets a value indicating whether the thread sampling is enabled.
/// Default is <c>false</c>.
/// </summary>
public bool ThreadSamplingEnabled { get; private set; }

/// <summary>
/// Gets a value indicating whether the allocation sampling is enabled.
/// Default is <c>false</c>.
/// </summary>
public bool AllocationSamplingEnabled { get; private set; }

/// <summary>
/// Gets a value of thread sampling interval.
/// Default is <c>1000</c>.
/// </summary>
public uint ThreadSamplingInterval { get; private set; }

/// <summary>
/// Gets a value of mam memory samples per minute.
/// Default is <c>200</c>.
/// </summary>
public uint MaxMemorySamplesPerMinute { get; private set; }

/// <summary>
/// Gets a value of export interval.
/// Default is <c>500ms</c>.
/// </summary>
public TimeSpan ExportInterval { get; private set; }

/// <summary>
/// Gets a value of export timeout.
/// Default is <c>5000ms</c>.
/// </summary>
public TimeSpan ExportTimeout { get; private set; }

protected override void OnLoad(Configuration configuration)
{
ThreadSamplingEnabled = configuration.GetBool(ConfigurationKeys.ContinuousProfiler.ThreadSamplingEnabled) ?? false;
AllocationSamplingEnabled = configuration.GetBool(ConfigurationKeys.ContinuousProfiler.AllocationSamplingEnabled) ?? false;
ThreadSamplingInterval = 1000u;
MaxMemorySamplesPerMinute = 200u;
ExportInterval = TimeSpan.FromMilliseconds(500);
ExportTimeout = TimeSpan.FromMilliseconds(5000);
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

namespace TestApplication.ContinuousProfiler;
#if NET6_0_OR_GREATER

namespace OpenTelemetry.AutoInstrumentation.ContinuousProfiler;

internal class AllocationSample
{
Expand All @@ -18,3 +20,4 @@ public AllocationSample(long allocationSizeBytes, string allocationTypeName, Thr

public ThreadSample ThreadSample { get; }
}
#endif
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#if NET6_0_OR_GREATER

using Google.Protobuf;
using OpenTelemetry.Proto.Common.V1;
using OpenTelemetry.Proto.Profiles.V1Experimental;

namespace TestApplication.ContinuousProfiler;
namespace OpenTelemetry.AutoInstrumentation.ContinuousProfiler;

internal class ExtendedPprofBuilder
{
Expand Down Expand Up @@ -208,3 +210,4 @@ public ulong GetOrAdd(string name, Action<AnyValue> setValue)
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#if NET6_0_OR_GREATER

using OpenTelemetry.Exporter;

namespace OpenTelemetry.AutoInstrumentation.ContinuousProfiler;

internal class OtlpOverHttpExporter
{
private readonly OtlpProfilerExporter _exporter;

public OtlpOverHttpExporter()
{
var transformer = new OtlpProfilerTransformer();
_exporter = new OtlpProfilerExporter(new OtlpExporterOptions { Protocol = OtlpExportProtocol.HttpProtobuf }, transformer);
}

public void ExportThreadSamples(byte[] buffer, int read, CancellationToken cancellationToken)
{
var exportData = Tuple.Create(buffer, read, "cpu");
Console.WriteLine("XXXXX-exporting CPU-begin");
_exporter.Export(new Batch<Tuple<byte[], int, string>>(new[] { exportData }, 1));
Console.WriteLine("XXXXX-exporting CPU-end");
}

public void ExportAllocationSamples(byte[] buffer, int read, CancellationToken cancellationToken)
{
var exportData = Tuple.Create(buffer, read, "memory");
Console.WriteLine("XXXXX-exporting memory-begin");
_exporter.Export(new Batch<Tuple<byte[], int, string>>(new[] { exportData }, 1));
Console.WriteLine("XXXXX-exporting memory-end");
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#if NET6_0_OR_GREATER

using System.Diagnostics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.Transmission;
using OtlpCollector = OpenTelemetry.Proto.Collector.Profiles.V1Experimental;
using OtlpResource = OpenTelemetry.Proto.Resource.V1;

namespace OpenTelemetry.AutoInstrumentation.ContinuousProfiler;

/// <summary>
/// Exporter consuming Tuple&lt;byte[], int, string&gt; and exporting the data using
/// the OpenTelemetry protocol (OTLP).
/// </summary>
internal sealed class OtlpProfilerExporter : BaseExporter<Tuple<byte[], int, string>>
{
private readonly OtlpExporterTransmissionHandler<OtlpCollector.ExportProfilesServiceRequest> transmissionHandler;
private readonly OtlpProfilerTransformer otlpProfilerTransformer;

private OtlpResource.Resource? processResource;

/// <summary>
/// Initializes a new instance of the <see cref="OtlpProfilerExporter"/> class.
/// </summary>
/// <param name="options">Configuration options for the exporter.</param>
/// <param name="otlpProfilerTransformer"><see cref="OtlpProfilerTransformer"/>.</param>
public OtlpProfilerExporter(OtlpExporterOptions options, OtlpProfilerTransformer otlpProfilerTransformer)
: this(options, otlpProfilerTransformer, sdkLimitOptions: new(), experimentalOptions: new(), transmissionHandler: null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="OtlpProfilerExporter"/> class.
/// </summary>
/// <param name="exporterOptions"><see cref="OtlpExporterOptions"/>.</param>
/// <param name="otlpProfilerTransformer"><see cref="OtlpProfilerTransformer"/>.</param>
/// <param name="sdkLimitOptions"><see cref="SdkLimitOptions"/>.</param>
/// <param name="experimentalOptions"><see cref="ExperimentalOptions"/>.</param>
/// <param name="transmissionHandler"><see cref="OtlpExporterTransmissionHandler{T}"/>.</param>
internal OtlpProfilerExporter(
OtlpExporterOptions exporterOptions,
OtlpProfilerTransformer otlpProfilerTransformer,
SdkLimitOptions sdkLimitOptions,
ExperimentalOptions experimentalOptions,
OtlpExporterTransmissionHandler<OtlpCollector.ExportProfilesServiceRequest>? transmissionHandler = null)
{
Debug.Assert(exporterOptions != null, "exporterOptions was null");
Debug.Assert(otlpProfilerTransformer != null, "otlpProfilerTransformer was null");
Debug.Assert(sdkLimitOptions != null, "sdkLimitOptions was null");
Debug.Assert(experimentalOptions != null, "experimentalOptions was null");

this.transmissionHandler = transmissionHandler ?? exporterOptions!.GetProfilesExportTransmissionHandler(experimentalOptions!);

this.otlpProfilerTransformer = otlpProfilerTransformer!;
}

internal OtlpResource.Resource ProcessResource
=> this.processResource ??= this.ParentProvider.GetResource().ToOtlpResource();

/// <inheritdoc/>
public override ExportResult Export(in Batch<Tuple<byte[], int, string>> profilerBatch)
{
// Prevents the exporter's gRPC and HTTP operations from being instrumented.
using var scope = SuppressInstrumentationScope.Begin();

try
{
OtlpCollector.ExportProfilesServiceRequest? request = this.otlpProfilerTransformer.BuildExportRequest(this.ProcessResource, profilerBatch);

if (request == null)
{
return ExportResult.Success;
}

if (!this.transmissionHandler.TrySubmitRequest(request))
{
return ExportResult.Failure;
}
}
catch (Exception ex)
{
OpenTelemetryProtocolExporterEventSource.Log.ExportMethodException(ex);
return ExportResult.Failure;
}

return ExportResult.Success;
}

/// <inheritdoc />
protected override bool OnShutdown(int timeoutMilliseconds)
{
return this.transmissionHandler?.Shutdown(timeoutMilliseconds) ?? true;
}
}
#endif
Loading
Loading