Skip to content

Commit

Permalink
[OneCollector] Add benchmark project (#1088)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeBlanch authored Mar 16, 2023
1 parent 5f587d4 commit 8f8d153
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/component_owners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ components:
- Yun-Ting
test/OpenTelemetry.Exporter.Instana.Tests/:
- zivaninstana
test/OpenTelemetry.Exporter.OneCollector.Benchmarks/:
- codeblanch
- reyang
test/OpenTelemetry.Exporter.OneCollector.Tests/:
- codeblanch
- reyang
Expand Down
7 changes: 7 additions & 0 deletions opentelemetry-dotnet-contrib.sln
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.PersistentSto
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.PersistentStorage.FileSystem.Tests", "test\OpenTelemetry.PersistentStorage.FileSystem.Tests\OpenTelemetry.PersistentStorage.FileSystem.Tests.csproj", "{C7215B69-0D77-4D52-AFBB-A6662249B3AC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.OneCollector.Benchmarks", "test\OpenTelemetry.Exporter.OneCollector.Benchmarks\OpenTelemetry.Exporter.OneCollector.Benchmarks.csproj", "{C42868C8-968A-473F-AC39-AC97C5D47E84}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -539,6 +541,10 @@ Global
{C7215B69-0D77-4D52-AFBB-A6662249B3AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7215B69-0D77-4D52-AFBB-A6662249B3AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7215B69-0D77-4D52-AFBB-A6662249B3AC}.Release|Any CPU.Build.0 = Release|Any CPU
{C42868C8-968A-473F-AC39-AC97C5D47E84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C42868C8-968A-473F-AC39-AC97C5D47E84}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C42868C8-968A-473F-AC39-AC97C5D47E84}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C42868C8-968A-473F-AC39-AC97C5D47E84}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -622,6 +628,7 @@ Global
{EC73B88E-D544-4A6A-90D5-E291035FEA35} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
{74EF2C61-9176-4D4E-91D3-E17E28054FF8} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
{C7215B69-0D77-4D52-AFBB-A6662249B3AC} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
{C42868C8-968A-473F-AC39-AC97C5D47E84} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B0816796-CDB3-47D7-8C3C-946434DE3B66}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// <copyright file="LogRecordCommonSchemaJsonHttpPostBenchmarks.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System.Diagnostics;
using System.Net;
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;

namespace OpenTelemetry.Exporter.OneCollector.Benchmarks;

[MemoryDiagnoser]
public class LogRecordCommonSchemaJsonHttpPostBenchmarks
{
private static readonly MethodInfo LogRecordSetScopeProviderMethodInfo = typeof(LogRecord).GetProperty("ScopeProvider", BindingFlags.Instance | BindingFlags.NonPublic)?.SetMethod
?? throw new InvalidOperationException("LogRecord.ScopeProvider.Set could not be found reflectively.");

private LogRecord[]? logRecords;
private OneCollectorExporter<LogRecord>? exporter;

[Params(1, 10, 100)]
public int NumberOfBatches { get; set; }

[Params(1000, 10_000)]
public int NumberOfLogRecordsPerBatch { get; set; }

[Params(true, false)]
public bool EnableCompression { get; set; }

[GlobalSetup]
public void GlobalSetup()
{
this.logRecords = new LogRecord[this.NumberOfLogRecordsPerBatch];

for (int i = 0; i < this.NumberOfLogRecordsPerBatch; i++)
{
this.logRecords[i] = CreateLogRecord(i);
}

var exporterOptions = new OneCollectorLogExporterOptions
{
ConnectionString = "InstrumentationKey=token-extrainformation",
};

exporterOptions.Validate();

var transportOptions = exporterOptions.TransportOptions;

transportOptions.HttpCompression = this.EnableCompression
? OneCollectorExporterHttpTransportCompressionType.Deflate
: OneCollectorExporterHttpTransportCompressionType.None;

var sink = new WriteDirectlyToTransportSink<LogRecord>(
new LogRecordCommonSchemaJsonSerializer(
new EventNameManager(exporterOptions.DefaultEventNamespace, exporterOptions.DefaultEventName),
exporterOptions.TenantToken!,
exporterOptions.SerializationOptions.ExceptionStackTraceHandling,
transportOptions.MaxPayloadSizeInBytes == -1 ? int.MaxValue : transportOptions.MaxPayloadSizeInBytes,
transportOptions.MaxNumberOfItemsPerPayload == -1 ? int.MaxValue : transportOptions.MaxNumberOfItemsPerPayload),
new HttpJsonPostTransport(
exporterOptions.InstrumentationKey!,
transportOptions.Endpoint,
transportOptions.HttpCompression,
new NoopHttpClient()));

this.exporter = new OneCollectorExporter<LogRecord>(sink);
}

[GlobalCleanup]
public void GlobalCleanup()
{
this.exporter?.Dispose();
}

[Benchmark]
public void Export()
{
for (int i = 0; i < this.NumberOfBatches; i++)
{
this.exporter!.Export(new Batch<LogRecord>(this.logRecords!, this.logRecords!.Length));
}
}

private static LogRecord CreateLogRecord(int index)
{
var logRecord = (LogRecord)Activator.CreateInstance(typeof(LogRecord), nonPublic: true)!;

logRecord.Timestamp = DateTime.UtcNow;
logRecord.CategoryName = typeof(LogRecordCommonSchemaJsonHttpPostBenchmarks).FullName;
logRecord.LogLevel = LogLevel.Information;

if (index % 2 == 0)
{
if (index % 4 == 0)
{
logRecord.EventId = new EventId(2, "MyEvent");
}
else
{
logRecord.EventId = new EventId(1);
}

logRecord.StateValues = new List<KeyValuePair<string, object?>>
{
new KeyValuePair<string, object?>("userId", 18),
new KeyValuePair<string, object?>("greeting", "hello world"),
new KeyValuePair<string, object?>("{OriginalFormat}", "Structured logging {userId} {greeting}"),
};

if (index % 3 == 0)
{
var scopeProvider = new ScopeProvider(
new List<KeyValuePair<string, object?>> { new KeyValuePair<string, object?>("scope1Key1", "scope1Value1"), new KeyValuePair<string, object?>("scope1Key2", "scope1Value2") },
new List<KeyValuePair<string, object?>> { new KeyValuePair<string, object?>("scope2Key1", "scope2Value1") });

LogRecordSetScopeProviderMethodInfo.Invoke(logRecord, new object[] { scopeProvider });
}
}
else
{
logRecord.FormattedMessage = "Non-structured log message";
}

if (index % 3 == 0)
{
logRecord.TraceId = ActivityTraceId.CreateRandom();
logRecord.SpanId = ActivitySpanId.CreateRandom();

if (index % 6 == 0)
{
logRecord.TraceFlags = ActivityTraceFlags.None;
}
else
{
logRecord.TraceFlags = ActivityTraceFlags.Recorded;
}
}

if (index % 9 == 0)
{
logRecord.Exception = new InvalidOperationException();
}

return logRecord;
}

private sealed class NoopHttpClient : IHttpClient
{
public HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
{
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
};
}
}

private sealed class ScopeProvider : IExternalScopeProvider
{
private readonly List<KeyValuePair<string, object?>>[] scopes;

public ScopeProvider(params List<KeyValuePair<string, object?>>[] scopes)
{
this.scopes = scopes;
}

public void ForEachScope<TState>(Action<object, TState> callback, TState state)
{
foreach (var scope in this.scopes)
{
callback(scope, state);
}
}

public IDisposable Push(object state)
{
throw new NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<Description>Benchmark project for OpenTelemetry .NET OneCollectorExporter.</Description>
<!-- OmniSharp/VS Code requires TargetFrameworks to be in descending order for IntelliSense and analysis. -->
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
<TargetFrameworks Condition="$(OS) == 'Windows_NT'">$(TargetFrameworks);net48;net472;net471;net47;net462</TargetFrameworks>
<Nullable>enable</Nullable>
<EnableAnalysis>true</EnableAnalysis>
<ImplicitUsings>true</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPkgVer)" />
<PackageReference Include="System.Net.Http" Version="$(SystemNetHttp)" Condition="'$(TargetFramework)' != 'net6.0' AND '$(TargetFramework)' != 'net7.0'" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.OneCollector\OpenTelemetry.Exporter.OneCollector.csproj" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions test/OpenTelemetry.Exporter.OneCollector.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// <copyright file="Program.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System.Diagnostics;
using BenchmarkDotNet.Running;

namespace OpenTelemetry.Exporter.OneCollector.Benchmarks;

internal static class Program
{
public static void Main(string[] args)
{
if (Debugger.IsAttached)
{
// Note: This block is so you can start the project with debugger
// attached and step through the code. It is helpful when working on
// it.
var benchmarks = new LogRecordCommonSchemaJsonHttpPostBenchmarks
{
NumberOfBatches = 10_000,
NumberOfLogRecordsPerBatch = 1000,
EnableCompression = true,
};

benchmarks.GlobalSetup();

benchmarks.Export();

benchmarks.GlobalCleanup();
}
else
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
}

0 comments on commit 8f8d153

Please sign in to comment.