Remove Jaeger Exporter - part 3: remove implementation and tests (#4796)

This commit is contained in:
xiang17 2023-08-22 10:49:28 -07:00 committed by GitHub
parent 2f6e1e5a48
commit 73df32b967
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 0 additions and 6091 deletions

View File

@ -60,10 +60,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testdata", "testdata", "{77
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{E359BB2B-9AEC-497D-B321-7DF2450C3B8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger", "src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj", "{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger.Tests", "test\OpenTelemetry.Exporter.Jaeger.Tests\OpenTelemetry.Exporter.Jaeger.Tests.csproj", "{21E69213-72D5-453F-BD00-75EF36AC4965}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Shims.OpenTracing", "src\OpenTelemetry.Shims.OpenTracing\OpenTelemetry.Shims.OpenTracing.csproj", "{AAC408FE-40EF-4479-97D9-697F2C1A0B28}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Shims.OpenTracing.Tests", "test\OpenTelemetry.Shims.OpenTracing.Tests\OpenTelemetry.Shims.OpenTracing.Tests.csproj", "{49A7853F-5B6F-4B65-A781-7D29A1C92164}"
@ -342,14 +338,6 @@ Global
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A47F6A8-63E5-4237-8046-94CAF321E797}.Release|Any CPU.Build.0 = Release|Any CPU
{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}.Release|Any CPU.Build.0 = Release|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.Build.0 = Release|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAC408FE-40EF-4479-97D9-697F2C1A0B28}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@ -1,29 +0,0 @@
OpenTelemetry.Exporter.JaegerExporter
OpenTelemetry.Exporter.JaegerExporter.JaegerExporter(OpenTelemetry.Exporter.JaegerExporterOptions options) -> void
OpenTelemetry.Exporter.JaegerExporterOptions
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.get -> string
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.get -> int
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions<System.Diagnostics.Activity>
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.get -> System.Uri
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.get -> System.Func<System.Net.Http.HttpClient>
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.JaegerExporterOptions() -> void
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.get -> int?
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.get -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.set -> void
OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.HttpBinaryThrift = 1 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.UdpCompactThrift = 0 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Trace.JaegerExporterHelperExtensions
override OpenTelemetry.Exporter.JaegerExporter.Dispose(bool disposing) -> void
override OpenTelemetry.Exporter.JaegerExporter.Export(in OpenTelemetry.Batch<System.Diagnostics.Activity> activityBatch) -> OpenTelemetry.ExportResult
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder

View File

@ -1,29 +0,0 @@
OpenTelemetry.Exporter.JaegerExporter
OpenTelemetry.Exporter.JaegerExporter.JaegerExporter(OpenTelemetry.Exporter.JaegerExporterOptions options) -> void
OpenTelemetry.Exporter.JaegerExporterOptions
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.get -> string
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.get -> int
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions<System.Diagnostics.Activity>
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.get -> System.Uri
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.get -> System.Func<System.Net.Http.HttpClient>
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.JaegerExporterOptions() -> void
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.get -> int?
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.get -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.set -> void
OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.HttpBinaryThrift = 1 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.UdpCompactThrift = 0 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Trace.JaegerExporterHelperExtensions
override OpenTelemetry.Exporter.JaegerExporter.Dispose(bool disposing) -> void
override OpenTelemetry.Exporter.JaegerExporter.Export(in OpenTelemetry.Batch<System.Diagnostics.Activity> activityBatch) -> OpenTelemetry.ExportResult
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder

View File

@ -1,29 +0,0 @@
OpenTelemetry.Exporter.JaegerExporter
OpenTelemetry.Exporter.JaegerExporter.JaegerExporter(OpenTelemetry.Exporter.JaegerExporterOptions options) -> void
OpenTelemetry.Exporter.JaegerExporterOptions
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.get -> string
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.get -> int
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions<System.Diagnostics.Activity>
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.get -> System.Uri
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.get -> System.Func<System.Net.Http.HttpClient>
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.JaegerExporterOptions() -> void
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.get -> int?
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.get -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.set -> void
OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.HttpBinaryThrift = 1 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.UdpCompactThrift = 0 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Trace.JaegerExporterHelperExtensions
override OpenTelemetry.Exporter.JaegerExporter.Dispose(bool disposing) -> void
override OpenTelemetry.Exporter.JaegerExporter.Export(in OpenTelemetry.Batch<System.Diagnostics.Activity> activityBatch) -> OpenTelemetry.ExportResult
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder

View File

@ -1,29 +0,0 @@
OpenTelemetry.Exporter.JaegerExporter
OpenTelemetry.Exporter.JaegerExporter.JaegerExporter(OpenTelemetry.Exporter.JaegerExporterOptions options) -> void
OpenTelemetry.Exporter.JaegerExporterOptions
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.get -> string
OpenTelemetry.Exporter.JaegerExporterOptions.AgentHost.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.get -> int
OpenTelemetry.Exporter.JaegerExporterOptions.AgentPort.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.get -> OpenTelemetry.BatchExportProcessorOptions<System.Diagnostics.Activity>
OpenTelemetry.Exporter.JaegerExporterOptions.BatchExportProcessorOptions.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.get -> System.Uri
OpenTelemetry.Exporter.JaegerExporterOptions.Endpoint.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.get -> OpenTelemetry.ExportProcessorType
OpenTelemetry.Exporter.JaegerExporterOptions.ExportProcessorType.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.get -> System.Func<System.Net.Http.HttpClient>
OpenTelemetry.Exporter.JaegerExporterOptions.HttpClientFactory.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.JaegerExporterOptions() -> void
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.get -> int?
OpenTelemetry.Exporter.JaegerExporterOptions.MaxPayloadSizeInBytes.set -> void
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.get -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExporterOptions.Protocol.set -> void
OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.HttpBinaryThrift = 1 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Exporter.JaegerExportProtocol.UdpCompactThrift = 0 -> OpenTelemetry.Exporter.JaegerExportProtocol
OpenTelemetry.Trace.JaegerExporterHelperExtensions
override OpenTelemetry.Exporter.JaegerExporter.Dispose(bool disposing) -> void
override OpenTelemetry.Exporter.JaegerExporter.Export(in OpenTelemetry.Batch<System.Diagnostics.Activity> activityBatch) -> OpenTelemetry.ExportResult
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, string name, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.JaegerExporterHelperExtensions.AddJaegerExporter(this OpenTelemetry.Trace.TracerProviderBuilder builder, System.Action<OpenTelemetry.Exporter.JaegerExporterOptions> configure) -> OpenTelemetry.Trace.TracerProviderBuilder

View File

@ -1,39 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TField
{
public TField(string name, TType type, short id)
{
Name = name;
Type = type;
ID = id;
}
public string Name { get; set; }
public TType Type { get; set; }
// ReSharper disable once InconsistentNaming - do not rename - it used for generation
public short ID { get; set; }
}
}

View File

@ -1,35 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TList
{
public TList(TType elementType, int count)
{
ElementType = elementType;
Count = count;
}
public TType ElementType { get; set; }
public int Count { get; set; }
}
}

View File

@ -1,38 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TMap
{
public TMap(TType keyType, TType valueType, int count)
{
KeyType = keyType;
ValueType = valueType;
Count = count;
}
public TType KeyType { get; set; }
public TType ValueType { get; set; }
public int Count { get; set; }
}
}

View File

@ -1,39 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TMessage
{
public TMessage(string name, TMessageType type, int seqid)
{
Name = name;
Type = type;
SeqID = seqid;
}
public string Name { get; set; }
public TMessageType Type { get; set; }
// ReSharper disable once InconsistentNaming - do not rename - it used for generation
public int SeqID { get; set; }
}
}

View File

@ -1,30 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal enum TMessageType
{
Call = 1,
Reply = 2,
Exception = 3,
Oneway = 4
}
}

View File

@ -1,40 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TSet
{
public TSet(TType elementType, int count)
{
ElementType = elementType;
Count = count;
}
public TSet(TList list)
: this(list.ElementType, list.Count)
{
}
public TType ElementType { get; set; }
public int Count { get; set; }
}
}

View File

@ -1,32 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal struct TStruct
{
public TStruct(string name)
{
Name = name;
}
public string Name { get; set; }
}
}

View File

@ -1,39 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
internal enum TType : byte
{
Stop = 0,
Void = 1,
Bool = 2,
Byte = 3,
Double = 4,
I16 = 6,
I32 = 8,
I64 = 10,
String = 11,
Struct = 12,
Map = 13,
Set = 14,
List = 15
}
}

View File

@ -1,231 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
using System;
using Thrift.Protocol.Entities;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
internal sealed class TBinaryProtocol : TProtocol
{
private const uint VersionMask = 0xffff0000;
private const uint Version1 = 0x80010000;
private readonly bool StrictRead;
private readonly bool StrictWrite;
// minimize memory allocations by means of an preallocated bytes buffer
// The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
private readonly byte[] PreAllocatedBuffer = new byte[128];
private static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
private static readonly TField StopField = new TField() { Type = TType.Stop };
public TBinaryProtocol(int initialCapacity = 8192)
: this(false, true, initialCapacity)
{
}
public TBinaryProtocol(bool strictRead, bool strictWrite, int initialCapacity = 8192)
: base(initialCapacity)
{
StrictRead = strictRead;
StrictWrite = strictWrite;
}
public override void WriteMessageBegin(TMessage message)
{
if (StrictWrite)
{
var version = Version1 | (uint)message.Type;
WriteI32((int)version);
WriteString(message.Name);
WriteI32(message.SeqID);
}
else
{
WriteString(message.Name);
WriteByte((sbyte)message.Type);
WriteI32(message.SeqID);
}
}
public override void WriteMessageBegin(TMessage message, out int seqIdPosition)
{
if (StrictWrite)
{
var version = Version1 | (uint)message.Type;
WriteI32((int)version);
WriteString(message.Name);
seqIdPosition = (int)Transport.Position;
WriteI32(message.SeqID);
}
else
{
WriteString(message.Name);
WriteByte((sbyte)message.Type);
seqIdPosition = (int)Transport.Position;
WriteI32(message.SeqID);
}
}
public override void WriteMessageEnd()
{
}
public override void WriteStructBegin(TStruct @struct)
{
}
public override void WriteStructEnd()
{
}
public override void WriteFieldBegin(TField field)
{
WriteByte((sbyte)field.Type);
WriteI16(field.ID);
}
public override void WriteFieldEnd()
{
}
public override void WriteFieldStop()
{
WriteByte((sbyte)TType.Stop);
}
public override void WriteListBegin(TList list)
{
WriteByte((sbyte)list.ElementType);
WriteI32(list.Count);
}
public override void WriteListBegin(TList list, out int countPosition)
{
WriteByte((sbyte)list.ElementType);
countPosition = (int)Transport.Position;
WriteI32(list.Count);
}
public override void WriteListEnd()
{
}
public override void WriteBool(bool b)
{
WriteByte(b ? (sbyte)1 : (sbyte)0);
}
public override void WriteByte(sbyte b)
{
PreAllocatedBuffer[0] = (byte)b;
Transport.Write(PreAllocatedBuffer, 0, 1);
}
public override void WriteI16(short i16)
{
PreAllocatedBuffer[0] = (byte)(0xff & (i16 >> 8));
PreAllocatedBuffer[1] = (byte)(0xff & i16);
Transport.Write(PreAllocatedBuffer, 0, 2);
}
public override int WriteUI32(uint ui32, Span<byte> buffer)
{
if (buffer.Length < 4)
return 0;
buffer[0] = (byte)(0xff & (ui32 >> 24));
buffer[1] = (byte)(0xff & (ui32 >> 16));
buffer[2] = (byte)(0xff & (ui32 >> 8));
buffer[3] = (byte)(0xff & ui32);
return 4;
}
public override void WriteI32(int i32)
{
PreAllocatedBuffer[0] = (byte)(0xff & (i32 >> 24));
PreAllocatedBuffer[1] = (byte)(0xff & (i32 >> 16));
PreAllocatedBuffer[2] = (byte)(0xff & (i32 >> 8));
PreAllocatedBuffer[3] = (byte)(0xff & i32);
Transport.Write(PreAllocatedBuffer, 0, 4);
}
public override void WriteI64(long i64)
{
PreAllocatedBuffer[0] = (byte)(0xff & (i64 >> 56));
PreAllocatedBuffer[1] = (byte)(0xff & (i64 >> 48));
PreAllocatedBuffer[2] = (byte)(0xff & (i64 >> 40));
PreAllocatedBuffer[3] = (byte)(0xff & (i64 >> 32));
PreAllocatedBuffer[4] = (byte)(0xff & (i64 >> 24));
PreAllocatedBuffer[5] = (byte)(0xff & (i64 >> 16));
PreAllocatedBuffer[6] = (byte)(0xff & (i64 >> 8));
PreAllocatedBuffer[7] = (byte)(0xff & i64);
Transport.Write(PreAllocatedBuffer, 0, 8);
}
public override void WriteDouble(double d)
{
WriteI64(BitConverter.DoubleToInt64Bits(d));
}
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
public override void WriteBinary(ReadOnlySpan<byte> bytes)
{
WriteI32(bytes.Length);
Transport.Write(bytes);
}
#endif
public override void WriteBinary(byte[] bytes, int offset, int count)
{
WriteI32(count);
Transport.Write(bytes, offset, count);
}
public sealed class Factory : TProtocolFactory
{
private readonly bool StrictRead;
private readonly bool StrictWrite;
public Factory()
: this(false, true)
{
}
public Factory(bool strictRead, bool strictWrite)
{
StrictRead = strictRead;
StrictWrite = strictWrite;
}
public override TProtocol GetProtocol(int initialCapacity = 8192)
{
return new TBinaryProtocol(StrictRead, StrictWrite, initialCapacity);
}
}
}
}

View File

@ -1,434 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Thrift.Protocol.Entities;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
internal sealed class TCompactProtocol : TProtocol
{
private const byte ProtocolId = 0x82;
private const byte Version = 1;
private const byte VersionMask = 0x1f; // 0001 1111
private const byte TypeMask = 0xE0; // 1110 0000
private const byte TypeBits = 0x07; // 0000 0111
private const int TypeShiftAmount = 5;
private static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
private static readonly TField StopField = new TField(string.Empty, TType.Stop, 0);
private const byte NoTypeOverride = 0xFF;
// ReSharper disable once InconsistentNaming
private static readonly byte[] TTypeToCompactType = new byte[16];
private static readonly TType[] CompactTypeToTType = new TType[13];
/// <summary>
/// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
/// </summary>
private readonly Stack<short> _lastField = new Stack<short>(15);
/// <summary>
/// If we encounter a boolean field begin, save the TField here so it can have the value incorporated.
/// </summary>
private TField? _booleanField;
private short _lastFieldId;
// minimize memory allocations by means of an preallocated bytes buffer
// The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
private readonly byte[] PreAllocatedBuffer = new byte[128];
private struct VarInt
{
public byte[] bytes;
public int count;
}
// minimize memory allocations by means of an preallocated VarInt buffer
private VarInt PreAllocatedVarInt = new VarInt()
{
bytes = new byte[10], // see Int64ToVarInt()
count = 0
};
private readonly byte[] EmptyUInt32Buffer = new byte[5];
public TCompactProtocol(int initialCapacity = 8192)
: base(initialCapacity)
{
TTypeToCompactType[(int)TType.Stop] = Types.Stop;
TTypeToCompactType[(int)TType.Bool] = Types.BooleanTrue;
TTypeToCompactType[(int)TType.Byte] = Types.Byte;
TTypeToCompactType[(int)TType.I16] = Types.I16;
TTypeToCompactType[(int)TType.I32] = Types.I32;
TTypeToCompactType[(int)TType.I64] = Types.I64;
TTypeToCompactType[(int)TType.Double] = Types.Double;
TTypeToCompactType[(int)TType.String] = Types.Binary;
TTypeToCompactType[(int)TType.List] = Types.List;
TTypeToCompactType[(int)TType.Set] = Types.Set;
TTypeToCompactType[(int)TType.Map] = Types.Map;
TTypeToCompactType[(int)TType.Struct] = Types.Struct;
CompactTypeToTType[Types.Stop] = TType.Stop;
CompactTypeToTType[Types.BooleanTrue] = TType.Bool;
CompactTypeToTType[Types.BooleanFalse] = TType.Bool;
CompactTypeToTType[Types.Byte] = TType.Byte;
CompactTypeToTType[Types.I16] = TType.I16;
CompactTypeToTType[Types.I32] = TType.I32;
CompactTypeToTType[Types.I64] = TType.I64;
CompactTypeToTType[Types.Double] = TType.Double;
CompactTypeToTType[Types.Binary] = TType.String;
CompactTypeToTType[Types.List] = TType.List;
CompactTypeToTType[Types.Set] = TType.Set;
CompactTypeToTType[Types.Map] = TType.Map;
CompactTypeToTType[Types.Struct] = TType.Struct;
}
public override void Reset()
{
_lastField.Clear();
_lastFieldId = 0;
base.Reset();
}
public override void WriteMessageBegin(TMessage message)
{
PreAllocatedBuffer[0] = ProtocolId;
PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask));
Transport.Write(PreAllocatedBuffer, 0, 2);
Int32ToVarInt((uint)message.SeqID, ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
WriteString(message.Name);
}
public override void WriteMessageBegin(TMessage message, out int seqIdPosition)
{
PreAllocatedBuffer[0] = ProtocolId;
PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask));
Transport.Write(PreAllocatedBuffer, 0, 2);
seqIdPosition = (int)Transport.Position;
// Write empty bytes to reserve the space for the seqId to be written later on.
Transport.Write(EmptyUInt32Buffer, 0, 5);
WriteString(message.Name);
}
public override void WriteMessageEnd()
{
}
/// <summary>
/// Write a struct begin. This doesn't actually put anything on the wire. We
/// use it as an opportunity to put special placeholder markers on the field
/// stack so we can get the field id deltas correct.
/// </summary>
public override void WriteStructBegin(TStruct @struct)
{
_lastField.Push(_lastFieldId);
_lastFieldId = 0;
}
public override void WriteStructEnd()
{
_lastFieldId = _lastField.Pop();
}
private void WriteFieldBeginInternal(TField field, byte fieldType)
{
// if there's a exType override passed in, use that. Otherwise ask GetCompactType().
if (fieldType == NoTypeOverride)
fieldType = GetCompactType(field.Type);
// check if we can use delta encoding for the field id
if (field.ID > _lastFieldId)
{
var delta = field.ID - _lastFieldId;
if (delta <= 15)
{
// Write them together
PreAllocatedBuffer[0] = (byte)((delta << 4) | fieldType);
Transport.Write(PreAllocatedBuffer, 0, 1);
_lastFieldId = field.ID;
return;
}
}
// Write them separate
PreAllocatedBuffer[0] = fieldType;
Transport.Write(PreAllocatedBuffer, 0, 1);
WriteI16(field.ID);
_lastFieldId = field.ID;
}
public override void WriteFieldBegin(TField field)
{
if (field.Type == TType.Bool)
{
_booleanField = field;
}
else
{
WriteFieldBeginInternal(field, NoTypeOverride);
}
}
public override void WriteFieldEnd()
{
}
public override void WriteFieldStop()
{
PreAllocatedBuffer[0] = Types.Stop;
Transport.Write(PreAllocatedBuffer, 0, 1);
}
public override void WriteListBegin(TList list)
{
if (list.Count <= 14)
{
PreAllocatedBuffer[0] = (byte)((list.Count << 4) | GetCompactType(list.ElementType));
Transport.Write(PreAllocatedBuffer, 0, 1);
}
else
{
PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(list.ElementType));
Transport.Write(PreAllocatedBuffer, 0, 1);
Int32ToVarInt((uint)list.Count, ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
}
}
public override void WriteListBegin(TList list, out int countPosition)
{
/*
Note: Compact sizing disabled because size might not be known initially.
if (list.Count <= 14)
{
PreAllocatedBuffer[0] = (byte)((list.Count << 4) | GetCompactType(list.ElementType));
Transport.Write(PreAllocatedBuffer, 0, 1);
}
else*/
{
PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(list.ElementType));
Transport.Write(PreAllocatedBuffer, 0, 1);
countPosition = (int)Transport.Position;
// Write empty bytes to reserve the space for the count to be written later on.
Transport.Write(EmptyUInt32Buffer, 0, 5);
}
}
public override void WriteListEnd()
{
}
public override void WriteBool(bool b)
{
/*
Write a boolean value. Potentially, this could be a boolean field, in
which case the field header info isn't written yet. If so, decide what the
right exType header is for the value and then Write the field header.
Otherwise, Write a single byte.
*/
if (_booleanField != null)
{
// we haven't written the field header yet
var type = b ? Types.BooleanTrue : Types.BooleanFalse;
WriteFieldBeginInternal(_booleanField.Value, type);
_booleanField = null;
}
else
{
// we're not part of a field, so just write the value.
PreAllocatedBuffer[0] = b ? Types.BooleanTrue : Types.BooleanFalse;
Transport.Write(PreAllocatedBuffer, 0, 1);
}
}
public override void WriteByte(sbyte b)
{
PreAllocatedBuffer[0] = (byte)b;
Transport.Write(PreAllocatedBuffer, 0, 1);
}
public override void WriteI16(short i16)
{
Int32ToVarInt(IntToZigzag(i16), ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
}
private static void Int32ToVarInt(uint n, ref VarInt varint)
{
// Write an i32 as a varint. Results in 1 - 5 bytes on the wire.
varint.count = 0;
Debug.Assert(varint.bytes.Length >= 5);
while (true)
{
if ((n & ~0x7F) == 0)
{
varint.bytes[varint.count++] = (byte)n;
break;
}
varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
n >>= 7;
}
}
public override void WriteI32(int i32)
{
Int32ToVarInt(IntToZigzag(i32), ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
}
public override int WriteUI32(uint ui32, Span<byte> buffer)
{
if (buffer.Length < 5)
return 0;
buffer[0] = (byte)(0x80 | (ui32 & 0x7F));
ui32 >>= 7;
buffer[1] = (byte)(0x80 | (ui32 & 0x7F));
ui32 >>= 7;
buffer[2] = (byte)(0x80 | (ui32 & 0x7F));
ui32 >>= 7;
buffer[3] = (byte)(0x80 | (ui32 & 0x7F));
ui32 >>= 7;
buffer[4] = (byte)ui32;
return 5;
}
static private void Int64ToVarInt(ulong n, ref VarInt varint)
{
// Write an i64 as a varint. Results in 1-10 bytes on the wire.
varint.count = 0;
Debug.Assert(varint.bytes.Length >= 10);
while (true)
{
if ((n & ~(ulong)0x7FL) == 0)
{
varint.bytes[varint.count++] = (byte)n;
break;
}
varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
n >>= 7;
}
}
public override void WriteI64(long i64)
{
Int64ToVarInt(LongToZigzag(i64), ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
}
public override void WriteDouble(double d)
{
FixedLongToBytes(BitConverter.DoubleToInt64Bits(d), PreAllocatedBuffer, 0);
Transport.Write(PreAllocatedBuffer, 0, 8);
}
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
public override void WriteBinary(ReadOnlySpan<byte> bytes)
{
Int32ToVarInt((uint)bytes.Length, ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
Transport.Write(bytes);
}
#endif
public override void WriteBinary(byte[] bytes, int offset, int count)
{
Int32ToVarInt((uint)count, ref PreAllocatedVarInt);
Transport.Write(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count);
Transport.Write(bytes, offset, count);
}
private static byte GetCompactType(TType ttype)
{
// Given a TType value, find the appropriate TCompactProtocol.Types constant.
return TTypeToCompactType[(int)ttype];
}
private static ulong LongToZigzag(long n)
{
// Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint
return (ulong)(n << 1) ^ (ulong)(n >> 63);
}
private static uint IntToZigzag(int n)
{
// Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint
return (uint)(n << 1) ^ (uint)(n >> 31);
}
private static void FixedLongToBytes(long n, byte[] buf, int off)
{
// Convert a long into little-endian bytes in buf starting at off and going until off+7.
buf[off + 0] = (byte)(n & 0xff);
buf[off + 1] = (byte)((n >> 8) & 0xff);
buf[off + 2] = (byte)((n >> 16) & 0xff);
buf[off + 3] = (byte)((n >> 24) & 0xff);
buf[off + 4] = (byte)((n >> 32) & 0xff);
buf[off + 5] = (byte)((n >> 40) & 0xff);
buf[off + 6] = (byte)((n >> 48) & 0xff);
buf[off + 7] = (byte)((n >> 56) & 0xff);
}
public sealed class Factory : TProtocolFactory
{
public override TProtocol GetProtocol(int initialCapacity = 8192)
{
return new TCompactProtocol(initialCapacity);
}
}
/// <summary>
/// All of the on-wire exType codes.
/// </summary>
private static class Types
{
public const byte Stop = 0x00;
public const byte BooleanTrue = 0x01;
public const byte BooleanFalse = 0x02;
public const byte Byte = 0x03;
public const byte I16 = 0x04;
public const byte I32 = 0x05;
public const byte I64 = 0x06;
public const byte Double = 0x07;
public const byte Binary = 0x08;
public const byte List = 0x09;
public const byte Set = 0x0A;
public const byte Map = 0x0B;
public const byte Struct = 0x0C;
}
}
}

View File

@ -1,189 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
using System;
using System.Buffers;
using System.IO;
using System.Text;
using Thrift.Protocol.Entities;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
internal abstract class TProtocol : IDisposable
{
public const int DefaultRecursionDepth = 64;
private bool _isDisposed;
protected TProtocol(int initialCapacity = 8192)
{
Transport = new MemoryStream(initialCapacity);
RecursionLimit = DefaultRecursionDepth;
RecursionDepth = 0;
}
protected MemoryStream Transport { get; }
protected int RecursionDepth { get; set; }
protected int RecursionLimit { get; set; }
public ArraySegment<byte> WrittenData
{
get => new ArraySegment<byte>(Transport.GetBuffer(), 0, (int)Transport.Length);
}
public int Position
{
get => (int)Transport.Position;
set => Transport.Position = value;
}
public int Length => (int)Transport.Length;
public void Clear(int offset = 0)
{
if (offset > Transport.Length)
throw new ArgumentOutOfRangeException(nameof(offset));
Transport.Position = offset;
Transport.SetLength(offset);
}
public virtual void Reset()
{
RecursionDepth = 0;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void IncrementRecursionDepth()
{
if (RecursionDepth >= RecursionLimit)
{
throw new TProtocolException(TProtocolException.DEPTH_LIMIT, $"Depth of recursion exceeded the limit: {RecursionLimit}");
}
++RecursionDepth;
}
public void DecrementRecursionDepth()
{
--RecursionDepth;
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
Transport.Dispose();
}
}
_isDisposed = true;
}
public abstract void WriteMessageBegin(TMessage message);
public abstract void WriteMessageBegin(TMessage message, out int seqIdPosition);
public abstract void WriteMessageEnd();
public abstract void WriteStructBegin(TStruct @struct);
public abstract void WriteStructEnd();
public abstract void WriteFieldBegin(TField field);
public abstract void WriteFieldEnd();
public abstract void WriteFieldStop();
public abstract void WriteListBegin(TList list);
public abstract void WriteListBegin(TList list, out int countPosition);
public abstract void WriteListEnd();
public abstract void WriteBool(bool b);
public abstract void WriteByte(sbyte b);
public abstract void WriteI16(short i16);
public abstract void WriteI32(int i32);
public abstract int WriteUI32(uint ui32, Span<byte> buffer);
public abstract void WriteI64(long i64);
public abstract void WriteDouble(double d);
public virtual void WriteString(string s)
{
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
if (s.Length <= 128)
{
Span<byte> buffer = stackalloc byte[256];
int numberOfBytes = Encoding.UTF8.GetBytes(s, buffer);
WriteBinary(buffer.Slice(0, numberOfBytes));
return;
}
#endif
var buf = ArrayPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(s));
try
{
var numberOfBytes = Encoding.UTF8.GetBytes(s, 0, s.Length, buf, 0);
WriteBinary(buf, 0, numberOfBytes);
}
finally
{
ArrayPool<byte>.Shared.Return(buf);
}
}
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
public abstract void WriteBinary(ReadOnlySpan<byte> bytes);
#endif
public abstract void WriteBinary(byte[] bytes, int offset, int count);
public void WriteRaw(byte[] bytes)
{
this.Transport.Write(bytes, 0, bytes.Length);
}
public void WriteRaw(byte[] bytes, int offset, int count)
{
this.Transport.Write(bytes, offset, count);
}
public void WriteRaw(ArraySegment<byte> bytes)
{
this.Transport.Write(bytes.Array, bytes.Offset, bytes.Count);
}
}
}

View File

@ -1,64 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
// ReSharper disable InconsistentNaming
using System;
namespace Thrift.Protocol
{
internal class TProtocolException : TException
{
// do not rename public constants - they used in generated files
public const int UNKNOWN = 0;
public const int INVALID_DATA = 1;
public const int NEGATIVE_SIZE = 2;
public const int SIZE_LIMIT = 3;
public const int BAD_VERSION = 4;
public const int NOT_IMPLEMENTED = 5;
public const int DEPTH_LIMIT = 6;
protected int Type = UNKNOWN;
public TProtocolException()
{
}
public TProtocolException(int type, Exception inner = null)
: base(string.Empty, inner)
{
Type = type;
}
public TProtocolException(int type, string message, Exception inner = null)
: base(message, inner)
{
Type = type;
}
public TProtocolException(string message, Exception inner = null)
: base(message, inner)
{
}
public int GetExceptionType()
{
return Type;
}
}
}

View File

@ -1,27 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
internal abstract class TProtocolFactory
{
public abstract TProtocol GetProtocol(int initialCapacity = 8192);
}
}

View File

@ -1,26 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
namespace Thrift.Protocol
{
internal interface TUnionBase
{
void Write(TProtocol tProtocol);
}
}

View File

@ -1,9 +0,0 @@
# OpenTelemetry - Jaeger Exporter - Apache Thrift
This folder contains a stripped-down and customized fork of the [ApacheThrift
0.13.0.1](https://www.nuget.org/packages/ApacheThrift/0.13.0.1) library from the
[apache/thrift](https://github.com/apache/thrift/tree/0.13.0) repo. Only the
client bits we need to transmit spans to Jaeger using the compact Thrift
protocol over UDP and binary Thrift over HTTP are included. Further
customizations have been made to improve the performance of our specific use
cases.

View File

@ -1,36 +0,0 @@
// <auto-generated/> (Turns off StyleCop analysis in this file.)
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you 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.
using System;
namespace Thrift
{
// ReSharper disable once InconsistentNaming
internal class TException : Exception
{
public TException()
{
}
public TException(string message, Exception inner)
: base(message, inner)
{
}
}
}

View File

@ -1,28 +0,0 @@
// <copyright file="AssemblyInfo.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.Runtime.CompilerServices;
#if SIGNED
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Jaeger.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")]
[assembly: InternalsVisibleTo("Benchmarks, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")]
// Used by Moq.
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
#else
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Jaeger.Tests")]
[assembly: InternalsVisibleTo("Benchmarks")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Used by Moq.
#endif

View File

@ -1,378 +0,0 @@
# Changelog
## Unreleased
## 1.6.0-rc.1
Released 2023-Aug-21
## 1.6.0-alpha.1
Released 2023-Jul-12
## 1.5.1
Released 2023-Jun-26
## 1.5.0
Released 2023-Jun-05
## 1.5.0-rc.1
Released 2023-May-25
* Added direct reference to `System.Text.Encodings.Web` with minimum version of
`4.7.2` in response to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377).
## 1.5.0-alpha.2
Released 2023-Mar-31
* Enabled performance optimizations for .NET 6.0+ runtimes.
([#4349](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4349))
## 1.5.0-alpha.1
Released 2023-Mar-07
## 1.4.0
Released 2023-Feb-24
* Updated OTel SDK dependency to 1.4.0
## 1.4.0-rc.4
Released 2023-Feb-10
## 1.4.0-rc.3
Released 2023-Feb-01
## 1.4.0-rc.2
Released 2023-Jan-09
## 1.4.0-rc.1
Released 2022-Dec-12
## 1.4.0-beta.3
Released 2022-Nov-07
* Bumped the minimum required version of `System.Text.Json` to 4.7.2 in response
to [CVE-2021-26701](https://github.com/dotnet/runtime/issues/49377).
([#3789](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3789))
## 1.4.0-beta.2
Released 2022-Oct-17
* Added support for loading environment variables from `IConfiguration` when
using the `AddJaegerExporter` extension
([#3720](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3720))
## 1.4.0-beta.1
Released 2022-Sep-29
* Added overloads which accept a name to the `TracerProviderBuilder`
`AddJaegerExporter` extension to allow for more fine-grained options
management
([#3656](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3656))
## 1.4.0-alpha.2
Released 2022-Aug-18
## 1.4.0-alpha.1
Released 2022-Aug-02
## 1.3.0
Released 2022-Jun-03
## 1.3.0-rc.2
Released 2022-June-1
* Improve the conversion and formatting of attribute values.
The list of data types that must be supported per the
[OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/common#attribute)
is more narrow than what the .NET OpenTelemetry SDK supports. Numeric
[built-in value types](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/built-in-types)
are supported by converting to a `long` or `double` as appropriate except for
numeric types that could cause overflow (`ulong`) or rounding (`decimal`)
which are converted to strings. Non-numeric built-in types - `string`,
`char`, `bool` are supported. All other types are converted to a `string`.
Array values are also supported.
([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281))
* Fix conversion of array-valued resource attributes. They were previously
converted to a string like "System.String[]".
([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281))
* Fix exporting of array-valued attributes on an `Activity`. Previously, each
item in the array would result in a new tag on an exported `Activity`. Now,
array-valued attributes are serialzed to a JSON-array representation.
([#3281](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3281))
## 1.3.0-beta.2
Released 2022-May-16
* Removes net5.0 target and replaced with net6.0
as .NET 5.0 is going out of support.
The package keeps netstandard2.1 target, so it
can still be used with .NET5.0 apps.
([#3147](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3147))
## 1.3.0-beta.1
Released 2022-Apr-15
* Removes .NET Framework 4.6.1. The minimum .NET Framework
version supported is .NET 4.6.2. ([#3190](https://github.com/open-telemetry/opentelemetry-dotnet/issues/3190))
## 1.2.0
Released 2022-Apr-15
## 1.2.0-rc5
Released 2022-Apr-12
## 1.2.0-rc4
Released 2022-Mar-30
* Added support for Activity Status and StatusDescription which were
added to Activity from `System.Diagnostics.DiagnosticSource` version 6.0.
Prior to version 6.0, setting the status of an Activity was provided by the
.NET OpenTelemetry API via the `Activity.SetStatus` extension method in the
`OpenTelemetry.Trace` namespace. Internally, this extension method added the
status as tags on the Activity: `otel.status_code` and `otel.status_description`.
Therefore, to maintain backward compatibility, the exporter falls back to using
these tags to infer status.
([#3073](https://github.com/open-telemetry/opentelemetry-dotnet/pull/3073))
## 1.2.0-rc3
Released 2022-Mar-04
* Change supported values for `OTEL_EXPORTER_JAEGER_PROTOCOL`
Supported values: `udp/thrift.compact` and `http/thrift.binary` defined
in the [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/9a0a3300c6269c2837a1d7c9c5232ec816f63222/specification/sdk-environment-variables.md?plain=1#L129).
([#2914](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2914))
* Change handling of `OTEL_EXPORTER_JAEGER_ENDPOINT` to require the path to
post. Previous versions of this library would append `/api/traces` to the
value specified in this variable, but now the application author must do so.
This change must also be made if you manually configure the
`JaegerExporterOptions` class - the `Endpoint` must now include the path.
For most environments, this will be `/api/traces`. The effective default
is still `http://localhost:14268/api/traces`. This was done to match
the clarified [specification](https://github.com/open-telemetry/opentelemetry-specification/pull/2333))
([#2847](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2847))
## 1.2.0-rc2
Released 2022-Feb-02
* Improved span duration's precision from millisecond to microsecond
([#2814](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2814))
## 1.2.0-rc1
Released 2021-Nov-29
## 1.2.0-beta2
Released 2021-Nov-19
* Changed `JaegerExporterOptions` constructor to throw
`FormatException` if it fails to parse any of the supported environment
variables.
* Added support for sending spans directly to a Jaeger Collector over HTTP
([#2574](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2574))
## 1.2.0-beta1
Released 2021-Oct-08
## 1.2.0-alpha4
Released 2021-Sep-23
## 1.2.0-alpha3
Released 2021-Sep-13
* `JaegerExporterOptions.BatchExportProcessorOptions` is initialized with
`BatchExportActivityProcessorOptions` which supports field value overriding
using `OTEL_BSP_SCHEDULE_DELAY`, `OTEL_BSP_EXPORT_TIMEOUT`,
`OTEL_BSP_MAX_QUEUE_SIZE`, `OTEL_BSP_MAX_EXPORT_BATCH_SIZE`
environmental variables as defined in the
[specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.5.0/specification/sdk-environment-variables.md#batch-span-processor).
([#2219](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2219))
## 1.2.0-alpha2
Released 2021-Aug-24
## 1.2.0-alpha1
Released 2021-Jul-23
* Removes .NET Framework 4.6 support. The minimum .NET Framework
version supported is .NET 4.6.1. ([#2138](https://github.com/open-telemetry/opentelemetry-dotnet/issues/2138))
* The `JaegerExporterOptions` defaults can be overridden using
`OTEL_EXPORTER_JAEGER_AGENT_HOST` and `OTEL_EXPORTER_JAEGER_AGENT_PORT`
environmental variables as defined in the
[specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter).
([#2123](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2123))
## 1.1.0
Released 2021-Jul-12
## 1.1.0-rc1
Released 2021-Jun-25
## 1.1.0-beta4
Released 2021-Jun-09
## 1.1.0-beta3
Released 2021-May-11
## 1.1.0-beta2
Released 2021-Apr-23
* When using OpenTelemetry.Extensions.Hosting you can now bind
`JaegerExporterOptions` to `IConfiguration` using the `Configure` extension
(ex:
`services.Configure<JaegerExporterOptions>(this.Configuration.GetSection("Jaeger"));`).
([#1889](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1889))
* Fixed data corruption when creating Jaeger Batch messages
([#1372](https://github.com/open-telemetry/opentelemetry-dotnet/issues/1372))
## 1.1.0-beta1
Released 2021-Mar-19
## 1.0.1
Released 2021-Feb-10
## 1.0.0-rc4
Released 2021-Feb-09
## 1.0.0-rc3
Released 2021-Feb-04
* Moved `JaegerExporter` and `JaegerExporterOptions` classes to
`OpenTelemetry.Exporter` namespace.
([#1770](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1770))
* Default ServiceName, if not found in Resource is obtained from SDK
using GetDefaultResource().
[#1768](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1768)
* Removed ProcessTags from JaegerExporterOptions. The alternate option is
to use Resource attributes.
## 1.0.0-rc2
Released 2021-Jan-29
* Changed `JaegerExporter` class and constructor from internal to public.
([#1612](https://github.com/open-telemetry/opentelemetry-dotnet/issues/1612))
* In `JaegerExporterOptions`: Exporter options now include a switch for Batch vs
Simple exporter, and settings for batch exporting properties.
* Jaeger will now set the `error` tag when `otel.status_code` is set to `ERROR`.
([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579)
[#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620))
* Jaeger will no longer send the `otel.status_code` tag if the value is `UNSET`.
([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609)
[#1620](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1620))
* Span Event.Name will now be populated as the `event` field on Jaeger Logs
instead of `message`.
([#1609](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1609))
* `JaegerExporter` batch format has changed to be compliant with the spec. This
may impact the way spans are displayed in Jaeger UI.
([#1732](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1732))
## 1.0.0-rc1.1
Released 2020-Nov-17
* Jaeger tags used for InstrumentationLibrary changed from library.name,
library.version to otel.library.name, otel.library.version respectively.
([#1513](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1513))
* The `JaegerExporter` class has been made internal.
([#1540](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1540))
* Removed `ServiceName` from options available on the `AddJaegerExporter`
extension. It is not required by the
[specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md).
([#1572](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1572))
## 0.8.0-beta.1
Released 2020-Nov-5
* Moving Jaeger Process from public to internal.
([#1421](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1421))
## 0.7.0-beta.1
Released 2020-Oct-16
* Renamed `MaxPacketSize` -> `MaxPayloadSizeInBytes` on `JaegerExporterOptions`.
Lowered the default value from 65,000 to 4096.
([#1247](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1274))
## 0.6.0-beta.1
Released 2020-Sep-15
* Removed `MaxFlushInterval` from `JaegerExporterOptions`. Batching is now
handled by `BatchExportActivityProcessor` exclusively.
([#1254](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1254))
## 0.5.0-beta.2
Released 2020-08-28
* Changed `JaegerExporter` to use `BatchExportActivityProcessor` by default.
([#1125](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1125))
* Span links will now be sent as `FOLLOWS_FROM` reference type. Previously they
were sent as `CHILD_OF`.
([#970](https://github.com/open-telemetry/opentelemetry-dotnet/pull/970))
* Fixed issue when span has both the `net.peer.name` and `net.peer.port`
attributes but did not include `net.peer.port` in the `peer.service` field.
([#1195](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1195))
* Renamed extension method from `UseJaegerExporter` to `AddJaegerExporter`.
## 0.4.0-beta.2
Released 2020-07-24
* First beta release
## 0.3.0-beta
Released 2020-07-23
* Initial release

View File

@ -1,82 +0,0 @@
// <copyright file="Batch.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 Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class Batch
{
public Batch(Process process, TProtocol protocol)
{
this.BatchBeginMessage = GenerateBeginMessage(process, protocol, out int spanCountPosition);
this.SpanCountPosition = spanCountPosition;
this.BatchEndMessage = GenerateEndMessage(protocol);
}
public byte[] BatchBeginMessage { get; }
public int SpanCountPosition { get; set; }
public byte[] BatchEndMessage { get; }
public int MinimumMessageSize => this.BatchBeginMessage.Length
+ this.BatchEndMessage.Length;
private static byte[] GenerateBeginMessage(Process process, TProtocol oprot, out int spanCountPosition)
{
var struc = new TStruct("Batch");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "process",
Type = TType.Struct,
ID = 1,
};
oprot.WriteFieldBegin(field);
process.Write(oprot);
oprot.WriteFieldEnd();
field.Name = "spans";
field.Type = TType.List;
field.ID = 2;
oprot.WriteFieldBegin(field);
oprot.WriteListBegin(new TList(TType.Struct, 0), out spanCountPosition);
byte[] beginMessage = oprot.WrittenData.ToArray();
oprot.Clear();
return beginMessage;
}
private static byte[] GenerateEndMessage(TProtocol oprot)
{
oprot.WriteListEnd();
oprot.WriteFieldEnd();
oprot.WriteFieldStop();
oprot.WriteStructEnd();
byte[] endMessage = oprot.WrittenData.ToArray();
oprot.Clear();
return endMessage;
}
}

View File

@ -1,73 +0,0 @@
// <copyright file="EmitBatchArgs.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 Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class EmitBatchArgs
{
public EmitBatchArgs(TProtocol protocol)
{
this.EmitBatchArgsBeginMessage = GenerateBeginMessage(protocol, out int seqIdPosition);
this.SeqIdPosition = seqIdPosition;
this.EmitBatchArgsEndMessage = GenerateEndMessage(protocol);
}
public byte[] EmitBatchArgsBeginMessage { get; }
public int SeqIdPosition { get; }
public byte[] EmitBatchArgsEndMessage { get; }
public int MinimumMessageSize => this.EmitBatchArgsBeginMessage.Length
+ this.EmitBatchArgsEndMessage.Length;
private static byte[] GenerateBeginMessage(TProtocol oprot, out int seqIdPosition)
{
oprot.WriteMessageBegin(new TMessage("emitBatch", TMessageType.Oneway, 0), out seqIdPosition);
var struc = new TStruct("emitBatch_args");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "batch",
Type = TType.Struct,
ID = 1,
};
oprot.WriteFieldBegin(field);
byte[] beginMessage = oprot.WrittenData.ToArray();
oprot.Clear();
return beginMessage;
}
private static byte[] GenerateEndMessage(TProtocol oprot)
{
oprot.WriteFieldEnd();
oprot.WriteFieldStop();
oprot.WriteStructEnd();
oprot.WriteMessageEnd();
byte[] endMessage = oprot.WrittenData.ToArray();
oprot.Clear();
return endMessage;
}
}

View File

@ -1,28 +0,0 @@
// <copyright file="IJaegerClient.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>
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal interface IJaegerClient : IDisposable
{
bool Connected { get; }
void Connect();
void Close();
int Send(byte[] buffer, int offset, int count);
}

View File

@ -1,62 +0,0 @@
// <copyright file="Int128.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.Runtime.InteropServices;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal readonly struct Int128
{
public static Int128 Empty;
private const int SpanIdBytes = 8;
private const int TraceIdBytes = 16;
public Int128(ActivitySpanId spanId)
{
Span<byte> bytes = stackalloc byte[SpanIdBytes];
spanId.CopyTo(bytes);
if (BitConverter.IsLittleEndian)
{
bytes.Reverse();
}
var longs = MemoryMarshal.Cast<byte, long>(bytes);
this.High = 0;
this.Low = longs[0];
}
public Int128(ActivityTraceId traceId)
{
Span<byte> bytes = stackalloc byte[TraceIdBytes];
traceId.CopyTo(bytes);
if (BitConverter.IsLittleEndian)
{
bytes.Reverse();
}
var longs = MemoryMarshal.Cast<byte, long>(bytes);
this.High = BitConverter.IsLittleEndian ? longs[1] : longs[0];
this.Low = BitConverter.IsLittleEndian ? longs[0] : longs[1];
}
public long High { get; }
public long Low { get; }
}

View File

@ -1,377 +0,0 @@
// <copyright file="JaegerActivityExtensions.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.Runtime.CompilerServices;
using OpenTelemetry.Internal;
using OpenTelemetry.Trace;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal static class JaegerActivityExtensions
{
internal const string JaegerErrorFlagTagName = "error";
private const int DaysPerYear = 365;
// Number of days in 4 years
private const int DaysPer4Years = (DaysPerYear * 4) + 1; // 1461
// Number of days in 100 years
private const int DaysPer100Years = (DaysPer4Years * 25) - 1; // 36524
// Number of days in 400 years
private const int DaysPer400Years = (DaysPer100Years * 4) + 1; // 146097
// Number of days from 1/1/0001 to 12/31/1969
private const int DaysTo1970 = (DaysPer400Years * 4) + (DaysPer100Years * 3) + (DaysPer4Years * 17) + DaysPerYear; // 719,162
private const long UnixEpochTicks = DaysTo1970 * TimeSpan.TicksPerDay;
private const long TicksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000;
private const long UnixEpochMicroseconds = UnixEpochTicks / TicksPerMicrosecond; // 62,135,596,800,000,000
public static JaegerSpan ToJaegerSpan(this Activity activity)
{
var jaegerTags = new TagEnumerationState
{
Tags = PooledList<JaegerTag>.Create(),
};
jaegerTags.EnumerateTags(activity);
if (activity.Status != ActivityStatusCode.Unset)
{
if (activity.Status == ActivityStatusCode.Ok)
{
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(SpanAttributeConstants.StatusCodeKey, JaegerTagType.STRING, vStr: "OK"));
}
else
{
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(SpanAttributeConstants.StatusCodeKey, JaegerTagType.STRING, vStr: "ERROR"));
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(JaegerErrorFlagTagName, JaegerTagType.BOOL, vBool: true));
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(SpanAttributeConstants.StatusDescriptionKey, JaegerTagType.STRING, vStr: activity.StatusDescription ?? string.Empty));
}
}
else if (jaegerTags.StatusCode.HasValue && jaegerTags.StatusCode != StatusCode.Unset)
{
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(
SpanAttributeConstants.StatusCodeKey,
JaegerTagType.STRING,
vStr: StatusHelper.GetTagValueForStatusCode(jaegerTags.StatusCode.Value)));
if (jaegerTags.StatusCode == StatusCode.Error)
{
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(JaegerErrorFlagTagName, JaegerTagType.BOOL, vBool: true));
PooledList<JaegerTag>.Add(
ref jaegerTags.Tags,
new JaegerTag(SpanAttributeConstants.StatusDescriptionKey, JaegerTagType.STRING, vStr: jaegerTags.StatusDescription ?? string.Empty));
}
}
string peerServiceName = null;
if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Producer)
{
PeerServiceResolver.Resolve(ref jaegerTags, out peerServiceName, out bool addAsTag);
if (peerServiceName != null && addAsTag)
{
PooledList<JaegerTag>.Add(ref jaegerTags.Tags, new JaegerTag(SemanticConventions.AttributePeerService, JaegerTagType.STRING, vStr: peerServiceName));
}
}
// The Span.Kind must translate into a tag.
// See https://opentracing.io/specification/conventions/
if (activity.Kind != ActivityKind.Internal)
{
string spanKind = null;
if (activity.Kind == ActivityKind.Server)
{
spanKind = "server";
}
else if (activity.Kind == ActivityKind.Client)
{
spanKind = "client";
}
else if (activity.Kind == ActivityKind.Consumer)
{
spanKind = "consumer";
}
else if (activity.Kind == ActivityKind.Producer)
{
spanKind = "producer";
}
if (spanKind != null)
{
PooledList<JaegerTag>.Add(ref jaegerTags.Tags, new JaegerTag("span.kind", JaegerTagType.STRING, vStr: spanKind));
}
}
var activitySource = activity.Source;
if (!string.IsNullOrEmpty(activitySource.Name))
{
PooledList<JaegerTag>.Add(ref jaegerTags.Tags, new JaegerTag("otel.library.name", JaegerTagType.STRING, vStr: activitySource.Name));
if (!string.IsNullOrEmpty(activitySource.Version))
{
PooledList<JaegerTag>.Add(ref jaegerTags.Tags, new JaegerTag("otel.library.version", JaegerTagType.STRING, vStr: activitySource.Version));
}
}
var traceId = Int128.Empty;
var spanId = Int128.Empty;
var parentSpanId = Int128.Empty;
if (activity.IdFormat == ActivityIdFormat.W3C)
{
// TODO: The check above should be enforced by the usage of the exporter. Perhaps enforce at higher-level.
traceId = new Int128(activity.TraceId);
spanId = new Int128(activity.SpanId);
if (activity.ParentSpanId != default)
{
parentSpanId = new Int128(activity.ParentSpanId);
}
}
return new JaegerSpan(
peerServiceName: peerServiceName,
traceIdLow: traceId.Low,
traceIdHigh: traceId.High,
spanId: spanId.Low,
parentSpanId: parentSpanId.Low,
operationName: activity.DisplayName,
flags: (activity.Context.TraceFlags & ActivityTraceFlags.Recorded) > 0 ? 0x1 : 0,
startTime: ToEpochMicroseconds(activity.StartTimeUtc),
duration: activity.Duration.Ticks / TicksPerMicrosecond,
references: activity.ToJaegerSpanRefs(),
tags: jaegerTags.Tags,
logs: activity.ToJaegerLogs());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PooledList<JaegerSpanRef> ToJaegerSpanRefs(this Activity activity)
{
LinkEnumerationState references = default;
references.EnumerateLinks(activity);
return references.SpanRefs;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PooledList<JaegerLog> ToJaegerLogs(this Activity activity)
{
EventEnumerationState logs = default;
logs.EnumerateEvents(activity);
return logs.Logs;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static JaegerLog ToJaegerLog(this in ActivityEvent timedEvent)
{
var jaegerTags = new EventTagsEnumerationState
{
Tags = PooledList<JaegerTag>.Create(),
};
jaegerTags.EnumerateTags(in timedEvent);
if (!jaegerTags.HasEvent)
{
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#events
PooledList<JaegerTag>.Add(ref jaegerTags.Tags, new JaegerTag("event", JaegerTagType.STRING, vStr: timedEvent.Name));
}
// TODO: Use the same function as JaegerConversionExtensions or check that the perf here is acceptable.
return new JaegerLog(timedEvent.Timestamp.ToEpochMicroseconds(), jaegerTags.Tags);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static JaegerSpanRef ToJaegerSpanRef(this in ActivityLink link)
{
var traceId = new Int128(link.Context.TraceId);
var spanId = new Int128(link.Context.SpanId);
// Assume FOLLOWS_FROM for links, mirrored from Java: https://github.com/open-telemetry/opentelemetry-java/pull/481#discussion_r312577862
var refType = JaegerSpanRefType.FOLLOWS_FROM;
return new JaegerSpanRef(refType, traceId.Low, traceId.High, spanId.Low);
}
public static long ToEpochMicroseconds(this DateTime utcDateTime)
{
// Truncate sub-microsecond precision before offsetting by the Unix Epoch to avoid
// the last digit being off by one for dates that result in negative Unix times
long microseconds = utcDateTime.Ticks / TicksPerMicrosecond;
return microseconds - UnixEpochMicroseconds;
}
public static long ToEpochMicroseconds(this DateTimeOffset timestamp)
{
// Truncate sub-microsecond precision before offsetting by the Unix Epoch to avoid
// the last digit being off by one for dates that result in negative Unix times
long microseconds = timestamp.UtcDateTime.Ticks / TicksPerMicrosecond;
return microseconds - UnixEpochMicroseconds;
}
private struct TagEnumerationState : PeerServiceResolver.IPeerServiceState
{
public PooledList<JaegerTag> Tags;
public string PeerService { get; set; }
public int? PeerServicePriority { get; set; }
public string HostName { get; set; }
public string IpAddress { get; set; }
public long Port { get; set; }
public StatusCode? StatusCode { get; set; }
public string StatusDescription { get; set; }
public void EnumerateTags(Activity activity)
{
foreach (ref readonly var tag in activity.EnumerateTagObjects())
{
if (tag.Value != null)
{
var key = tag.Key;
if (!JaegerTagTransformer.Instance.TryTransformTag(tag, out var jaegerTag))
{
continue;
}
if (jaegerTag.VStr != null)
{
PeerServiceResolver.InspectTag(ref this, key, jaegerTag.VStr);
if (key == SpanAttributeConstants.StatusCodeKey)
{
StatusCode? statusCode = StatusHelper.GetStatusCodeForTagValue(jaegerTag.VStr);
this.StatusCode = statusCode;
continue;
}
else if (key == SpanAttributeConstants.StatusDescriptionKey)
{
this.StatusDescription = jaegerTag.VStr;
continue;
}
}
else if (jaegerTag.VLong.HasValue)
{
PeerServiceResolver.InspectTag(ref this, key, jaegerTag.VLong.Value);
}
PooledList<JaegerTag>.Add(ref this.Tags, jaegerTag);
}
}
}
}
private struct LinkEnumerationState
{
public bool Created;
public PooledList<JaegerSpanRef> SpanRefs;
public void EnumerateLinks(Activity activity)
{
var enumerator = activity.EnumerateLinks();
if (enumerator.MoveNext())
{
this.SpanRefs = PooledList<JaegerSpanRef>.Create();
this.Created = true;
do
{
ref readonly var link = ref enumerator.Current;
PooledList<JaegerSpanRef>.Add(ref this.SpanRefs, link.ToJaegerSpanRef());
}
while (enumerator.MoveNext());
}
}
}
private struct EventEnumerationState
{
public bool Created;
public PooledList<JaegerLog> Logs;
public void EnumerateEvents(Activity activity)
{
var enumerator = activity.EnumerateEvents();
if (enumerator.MoveNext())
{
this.Logs = PooledList<JaegerLog>.Create();
this.Created = true;
do
{
ref readonly var @event = ref enumerator.Current;
PooledList<JaegerLog>.Add(ref this.Logs, @event.ToJaegerLog());
}
while (enumerator.MoveNext());
}
}
}
private struct EventTagsEnumerationState
{
public PooledList<JaegerTag> Tags;
public bool HasEvent;
public void EnumerateTags(in ActivityEvent @event)
{
foreach (ref readonly var tag in @event.EnumerateTagObjects())
{
if (JaegerTagTransformer.Instance.TryTransformTag(tag, out var result))
{
PooledList<JaegerTag>.Add(ref this.Tags, result);
if (tag.Key == "event")
{
this.HasEvent = true;
}
}
}
}
}
}

View File

@ -1,56 +0,0 @@
// <copyright file="JaegerExporterEventSource.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.Tracing;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
/// <summary>
/// EventSource events emitted from the project.
/// </summary>
[EventSource(Name = "OpenTelemetry-Exporter-Jaeger")]
internal sealed class JaegerExporterEventSource : EventSource
{
public static JaegerExporterEventSource Log = new();
[NonEvent]
public void FailedExport(Exception ex)
{
if (this.IsEnabled(EventLevel.Error, EventKeywords.All))
{
this.FailedExport(ex.ToInvariantString());
}
}
[Event(1, Message = "Failed to send spans: '{0}'", Level = EventLevel.Error)]
public void FailedExport(string exception)
{
this.WriteEvent(1, exception);
}
[Event(2, Message = "Unsupported attribute type '{0}' for '{1}'. Attribute will not be exported.", Level = EventLevel.Warning)]
public void UnsupportedAttributeType(string type, string key)
{
this.WriteEvent(2, type.ToString(), key);
}
[Event(3, Message = "{0} environment variable has an invalid value: '{1}'", Level = EventLevel.Warning)]
public void InvalidEnvironmentVariable(string key, string value)
{
this.WriteEvent(3, key, value);
}
}

View File

@ -1,29 +0,0 @@
// <copyright file="JaegerExporterException.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>
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
#pragma warning disable CA1032 // Implement standard exception constructors
#pragma warning disable CA1064 // Exceptions should be public
internal sealed class JaegerExporterException : Exception
#pragma warning restore CA1064 // Exceptions should be public
#pragma warning restore CA1032 // Implement standard exception constructors
{
public JaegerExporterException(string message, Exception originalException)
: base(message, originalException)
{
}
}

View File

@ -1,85 +0,0 @@
// <copyright file="JaegerHttpClient.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;
#if NETFRAMEWORK
using System.Net.Http;
#endif
using System.Net.Http.Headers;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class JaegerHttpClient : IJaegerClient
{
private static readonly MediaTypeHeaderValue ContentTypeHeader = new("application/vnd.apache.thrift.binary");
private readonly Uri endpoint;
private readonly HttpClient httpClient;
private bool disposed;
public JaegerHttpClient(Uri endpoint, HttpClient httpClient)
{
Debug.Assert(endpoint != null, "endpoint is null");
Debug.Assert(httpClient != null, "httpClient is null");
this.endpoint = endpoint;
this.httpClient = httpClient;
}
public bool Connected => true;
public void Close()
{
}
public void Connect()
{
}
public void Dispose()
{
if (this.disposed)
{
return;
}
this.httpClient.Dispose();
this.disposed = true;
}
public int Send(byte[] buffer, int offset, int count)
{
// Prevent Jaeger's HTTP operations from being instrumented.
using var scope = SuppressInstrumentationScope.Begin();
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, this.endpoint);
request.Content = new ByteArrayContent(buffer, offset, count)
{
Headers = { ContentType = ContentTypeHeader },
};
#if NET6_0_OR_GREATER
using HttpResponseMessage response = this.httpClient.Send(request);
#else
using HttpResponseMessage response = this.httpClient.SendAsync(request).GetAwaiter().GetResult();
#endif
response.EnsureSuccessStatusCode();
return count;
}
}

View File

@ -1,91 +0,0 @@
// <copyright file="JaegerLog.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.Text;
using OpenTelemetry.Internal;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal readonly struct JaegerLog : TUnionBase
{
public JaegerLog(long timestamp, in PooledList<JaegerTag> fields)
{
this.Timestamp = timestamp;
this.Fields = fields;
}
public long Timestamp { get; }
public PooledList<JaegerTag> Fields { get; }
public void Write(TProtocol oprot)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("Log");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "timestamp",
Type = TType.I64,
ID = 1,
};
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.Timestamp);
oprot.WriteFieldEnd();
field.Name = "fields";
field.Type = TType.List;
field.ID = 2;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, this.Fields.Count));
for (int i = 0; i < this.Fields.Count; i++)
{
this.Fields[i].Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
}
public override string ToString()
{
var sb = new StringBuilder("Log(");
sb.Append(", Timestamp: ");
sb.Append(this.Timestamp);
sb.Append(", Fields: ");
sb.Append(this.Fields);
sb.Append(')');
return sb.ToString();
}
}

View File

@ -1,278 +0,0 @@
// <copyright file="JaegerSpan.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.Text;
using OpenTelemetry.Internal;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal readonly struct JaegerSpan : TUnionBase
{
public JaegerSpan(
string peerServiceName,
long traceIdLow,
long traceIdHigh,
long spanId,
long parentSpanId,
string operationName,
int flags,
long startTime,
long duration,
in PooledList<JaegerSpanRef> references,
in PooledList<JaegerTag> tags,
in PooledList<JaegerLog> logs)
{
this.PeerServiceName = peerServiceName;
this.TraceIdLow = traceIdLow;
this.TraceIdHigh = traceIdHigh;
this.SpanId = spanId;
this.ParentSpanId = parentSpanId;
this.OperationName = operationName;
this.Flags = flags;
this.StartTime = startTime;
this.Duration = duration;
this.References = references;
this.Tags = tags;
this.Logs = logs;
}
public string PeerServiceName { get; }
public long TraceIdLow { get; }
public long TraceIdHigh { get; }
public long SpanId { get; }
public long ParentSpanId { get; }
public string OperationName { get; }
public PooledList<JaegerSpanRef> References { get; }
public int Flags { get; }
public long StartTime { get; }
public long Duration { get; }
public PooledList<JaegerTag> Tags { get; }
public PooledList<JaegerLog> Logs { get; }
public void Write(TProtocol oprot)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("Span");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "traceIdLow",
Type = TType.I64,
ID = 1,
};
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.TraceIdLow);
oprot.WriteFieldEnd();
field.Name = "traceIdHigh";
field.Type = TType.I64;
field.ID = 2;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.TraceIdHigh);
oprot.WriteFieldEnd();
field.Name = "spanId";
field.Type = TType.I64;
field.ID = 3;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.SpanId);
oprot.WriteFieldEnd();
field.Name = "parentSpanId";
field.Type = TType.I64;
field.ID = 4;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.ParentSpanId);
oprot.WriteFieldEnd();
field.Name = "operationName";
field.Type = TType.String;
field.ID = 5;
oprot.WriteFieldBegin(field);
oprot.WriteString(this.OperationName);
oprot.WriteFieldEnd();
if (!this.References.IsEmpty)
{
field.Name = "references";
field.Type = TType.List;
field.ID = 6;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, this.References.Count));
for (int i = 0; i < this.References.Count; i++)
{
this.References[i].Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
}
field.Name = "flags";
field.Type = TType.I32;
field.ID = 7;
oprot.WriteFieldBegin(field);
oprot.WriteI32(this.Flags);
oprot.WriteFieldEnd();
field.Name = "startTime";
field.Type = TType.I64;
field.ID = 8;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.StartTime);
oprot.WriteFieldEnd();
field.Name = "duration";
field.Type = TType.I64;
field.ID = 9;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.Duration);
oprot.WriteFieldEnd();
if (!this.Tags.IsEmpty)
{
field.Name = "JaegerTags";
field.Type = TType.List;
field.ID = 10;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, this.Tags.Count));
for (int i = 0; i < this.Tags.Count; i++)
{
this.Tags[i].Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
}
if (!this.Logs.IsEmpty)
{
field.Name = "logs";
field.Type = TType.List;
field.ID = 11;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, this.Logs.Count));
for (int i = 0; i < this.Logs.Count; i++)
{
this.Logs[i].Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
}
public void Return()
{
this.References.Return();
this.Tags.Return();
if (!this.Logs.IsEmpty)
{
for (int i = 0; i < this.Logs.Count; i++)
{
this.Logs[i].Fields.Return();
}
this.Logs.Return();
}
}
public override string ToString()
{
var sb = new StringBuilder("Span(");
sb.Append(", TraceIdLow: ");
sb.Append(this.TraceIdLow);
sb.Append(", TraceIdHigh: ");
sb.Append(this.TraceIdHigh);
sb.Append(", SpanId: ");
sb.Append(this.SpanId);
sb.Append(", ParentSpanId: ");
sb.Append(this.ParentSpanId);
sb.Append(", OperationName: ");
sb.Append(this.OperationName);
if (!this.References.IsEmpty)
{
sb.Append(", References: ");
sb.Append(this.References);
}
sb.Append(", Flags: ");
sb.Append(this.Flags);
sb.Append(", StartTime: ");
sb.Append(this.StartTime);
sb.Append(", Duration: ");
sb.Append(this.Duration);
if (!this.Tags.IsEmpty)
{
sb.Append(", JaegerTags: ");
sb.Append(this.Tags);
}
if (!this.Logs.IsEmpty)
{
sb.Append(", Logs: ");
sb.Append(this.Logs);
}
sb.Append(')');
return sb.ToString();
}
}

View File

@ -1,110 +0,0 @@
// <copyright file="JaegerSpanRef.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.Text;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal readonly struct JaegerSpanRef : TUnionBase
{
public JaegerSpanRef(JaegerSpanRefType refType, long traceIdLow, long traceIdHigh, long spanId)
{
this.RefType = refType;
this.TraceIdLow = traceIdLow;
this.TraceIdHigh = traceIdHigh;
this.SpanId = spanId;
}
public JaegerSpanRefType RefType { get; }
public long TraceIdLow { get; }
public long TraceIdHigh { get; }
public long SpanId { get; }
public void Write(TProtocol oprot)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("SpanRef");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "refType",
Type = TType.I32,
ID = 1,
};
oprot.WriteFieldBegin(field);
oprot.WriteI32((int)this.RefType);
oprot.WriteFieldEnd();
field.Name = "traceIdLow";
field.Type = TType.I64;
field.ID = 2;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.TraceIdLow);
oprot.WriteFieldEnd();
field.Name = "traceIdHigh";
field.Type = TType.I64;
field.ID = 3;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.TraceIdHigh);
oprot.WriteFieldEnd();
field.Name = "spanId";
field.Type = TType.I64;
field.ID = 4;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.SpanId);
oprot.WriteFieldEnd();
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
}
/// <summary>
/// <seealso cref="JaegerSpanRefType"/>
/// </summary>
/// <returns>A string representation of the object.</returns>
public override string ToString()
{
var sb = new StringBuilder("SpanRef(");
sb.Append(", RefType: ");
sb.Append(this.RefType);
sb.Append(", TraceIdLow: ");
sb.Append(this.TraceIdLow);
sb.Append(", TraceIdHigh: ");
sb.Append(this.TraceIdHigh);
sb.Append(", SpanId: ");
sb.Append(this.SpanId);
sb.Append(')');
return sb.ToString();
}
}

View File

@ -1,33 +0,0 @@
// <copyright file="JaegerSpanRefType.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>
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
/// <summary>
/// Represents the different types of Jaeger Spans.
/// </summary>
internal enum JaegerSpanRefType
{
/// <summary>
/// A child span.
/// </summary>
CHILD_OF = 0,
/// <summary>
/// A sibling span.
/// </summary>
FOLLOWS_FROM = 1,
}

View File

@ -1,180 +0,0 @@
// <copyright file="JaegerTag.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.Text;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal readonly struct JaegerTag : TUnionBase
{
public JaegerTag(
string key,
JaegerTagType vType,
string vStr = null,
double? vDouble = null,
bool? vBool = null,
long? vLong = null,
byte[] vBinary = null)
{
this.Key = key;
this.VType = vType;
this.VStr = vStr;
this.VDouble = vDouble;
this.VBool = vBool;
this.VLong = vLong;
this.VBinary = vBinary;
}
public string Key { get; }
public JaegerTagType VType { get; }
public string VStr { get; }
public double? VDouble { get; }
public bool? VBool { get; }
public long? VLong { get; }
public byte[] VBinary { get; }
public void Write(TProtocol oprot)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("Tag");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "key",
Type = TType.String,
ID = 1,
};
oprot.WriteFieldBegin(field);
oprot.WriteString(this.Key);
oprot.WriteFieldEnd();
field.Name = "vType";
field.Type = TType.I32;
field.ID = 2;
oprot.WriteFieldBegin(field);
oprot.WriteI32((int)this.VType);
oprot.WriteFieldEnd();
if (this.VStr != null)
{
field.Name = "vStr";
field.Type = TType.String;
field.ID = 3;
oprot.WriteFieldBegin(field);
oprot.WriteString(this.VStr);
oprot.WriteFieldEnd();
}
else if (this.VDouble.HasValue)
{
field.Name = "vDouble";
field.Type = TType.Double;
field.ID = 4;
oprot.WriteFieldBegin(field);
oprot.WriteDouble(this.VDouble.Value);
oprot.WriteFieldEnd();
}
else if (this.VBool.HasValue)
{
field.Name = "vBool";
field.Type = TType.Bool;
field.ID = 5;
oprot.WriteFieldBegin(field);
oprot.WriteBool(this.VBool.Value);
oprot.WriteFieldEnd();
}
else if (this.VLong.HasValue)
{
field.Name = "vLong";
field.Type = TType.I64;
field.ID = 6;
oprot.WriteFieldBegin(field);
oprot.WriteI64(this.VLong.Value);
oprot.WriteFieldEnd();
}
else if (this.VBinary != null)
{
field.Name = "vBinary";
field.Type = TType.String;
field.ID = 7;
oprot.WriteFieldBegin(field);
oprot.WriteBinary(this.VBinary, 0, this.VBinary.Length);
oprot.WriteFieldEnd();
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
}
public override string ToString()
{
var sb = new StringBuilder("Tag(");
sb.Append(", Key: ");
sb.Append(this.Key);
sb.Append(", VType: ");
sb.Append(this.VType);
if (this.VStr != null)
{
sb.Append(", VStr: ");
sb.Append(this.VStr);
}
if (this.VDouble.HasValue)
{
sb.Append(", VDouble: ");
sb.Append(this.VDouble);
}
if (this.VBool.HasValue)
{
sb.Append(", VBool: ");
sb.Append(this.VBool);
}
if (this.VLong.HasValue)
{
sb.Append(", VLong: ");
sb.Append(this.VLong);
}
if (this.VBinary != null)
{
sb.Append(", VBinary: ");
sb.Append(this.VBinary);
}
sb.Append(')');
return sb.ToString();
}
}

View File

@ -1,51 +0,0 @@
// <copyright file="JaegerTagTransformer.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 OpenTelemetry.Internal;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class JaegerTagTransformer : TagTransformer<JaegerTag>
{
private JaegerTagTransformer()
{
}
public static JaegerTagTransformer Instance { get; } = new();
protected override JaegerTag TransformIntegralTag(string key, long value)
{
return new JaegerTag(key, JaegerTagType.LONG, vLong: value);
}
protected override JaegerTag TransformFloatingPointTag(string key, double value)
{
return new JaegerTag(key, JaegerTagType.DOUBLE, vDouble: value);
}
protected override JaegerTag TransformBooleanTag(string key, bool value)
{
return new JaegerTag(key, JaegerTagType.BOOL, vBool: value);
}
protected override JaegerTag TransformStringTag(string key, string value)
{
return new JaegerTag(key, JaegerTagType.STRING, vStr: value);
}
protected override JaegerTag TransformArrayTag(string key, Array array)
=> this.TransformStringTag(key, TagTransformerJsonHelper.JsonSerializeArrayTag(array));
}

View File

@ -1,48 +0,0 @@
// <copyright file="JaegerTagType.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>
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
/// <summary>
/// Indicates the data type of a Jaeger tag.
/// </summary>
internal enum JaegerTagType
{
/// <summary>
/// Tag contains a string.
/// </summary>
STRING = 0,
/// <summary>
/// Tag contains a double.
/// </summary>
DOUBLE = 1,
/// <summary>
/// Tag contains a boolean.
/// </summary>
BOOL = 2,
/// <summary>
/// Tag contains a long.
/// </summary>
LONG = 3,
/// <summary>
/// Tag contains binary data.
/// </summary>
BINARY = 4,
}

View File

@ -1,58 +0,0 @@
// <copyright file="JaegerUdpClient.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.Net.Sockets;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class JaegerUdpClient : IJaegerClient
{
private readonly string host;
private readonly int port;
private readonly UdpClient client;
private bool disposed;
public JaegerUdpClient(string host, int port)
{
this.host = host;
this.port = port;
this.client = new UdpClient();
}
public bool Connected => this.client.Client.Connected;
public void Close() => this.client.Close();
public void Connect() => this.client.Connect(this.host, this.port);
public int Send(byte[] buffer, int offset, int count)
{
return this.client.Client.Send(buffer, offset, count, SocketFlags.None);
}
/// <inheritdoc/>
public void Dispose()
{
if (this.disposed)
{
return;
}
this.client.Dispose();
this.disposed = true;
}
}

View File

@ -1,94 +0,0 @@
// <copyright file="Process.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.Text;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
namespace OpenTelemetry.Exporter.Jaeger.Implementation;
internal sealed class Process
{
public string ServiceName { get; set; }
public Dictionary<string, JaegerTag> Tags { get; set; }
public override string ToString()
{
var sb = new StringBuilder("Process(");
sb.Append(", ServiceName: ");
sb.Append(this.ServiceName);
if (this.Tags != null)
{
sb.Append(", Tags: ");
sb.Append(this.Tags);
}
sb.Append(')');
return sb.ToString();
}
public void Write(TProtocol oprot)
{
oprot.IncrementRecursionDepth();
try
{
var struc = new TStruct("Process");
oprot.WriteStructBegin(struc);
var field = new TField
{
Name = "serviceName",
Type = TType.String,
ID = 1,
};
oprot.WriteFieldBegin(field);
oprot.WriteString(this.ServiceName);
oprot.WriteFieldEnd();
if (this.Tags != null)
{
field.Name = "tags";
field.Type = TType.List;
field.ID = 2;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, this.Tags.Count));
foreach (var jt in this.Tags)
{
jt.Value.Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
}
}

View File

@ -1,35 +0,0 @@
// <copyright file="ShimExtensions.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>
#if NETSTANDARD2_0 || NETFRAMEWORK
namespace System;
internal static class ShimExtensions
{
public static byte[] ToArray(this ArraySegment<byte> arraySegment)
{
int count = arraySegment.Count;
if (count == 0)
{
return Array.Empty<byte>();
}
var array = new byte[count];
Array.Copy(arraySegment.Array, arraySegment.Offset, array, 0, count);
return array;
}
}
#endif

View File

@ -1,39 +0,0 @@
// <copyright file="JaegerExportProtocol.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>
namespace OpenTelemetry.Exporter;
/// <summary>
/// Defines the exporter protocols supported by the <see cref="JaegerExporter"/>.
/// </summary>
public enum JaegerExportProtocol : byte
{
/// <summary>
/// Compact thrift protocol over UDP.
/// </summary>
/// <remarks>
/// Note: Supported by Jaeger Agents only.
/// </remarks>
UdpCompactThrift = 0,
/// <summary>
/// Binary thrift protocol over HTTP.
/// </summary>
/// <remarks>
/// Note: Supported by Jaeger Collectors only.
/// </remarks>
HttpBinaryThrift = 1,
}

View File

@ -1,287 +0,0 @@
// <copyright file="JaegerExporter.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.Runtime.CompilerServices;
using OpenTelemetry.Exporter.Jaeger.Implementation;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;
using Thrift.Protocol;
using Process = OpenTelemetry.Exporter.Jaeger.Implementation.Process;
namespace OpenTelemetry.Exporter;
public class JaegerExporter : BaseExporter<Activity>
{
internal uint NumberOfSpansInCurrentBatch;
private readonly byte[] uInt32Storage = new byte[8];
private readonly int maxPayloadSizeInBytes;
private readonly IJaegerClient client;
private readonly TProtocol batchWriter;
private readonly TProtocol spanWriter;
private readonly bool sendUsingEmitBatchArgs;
private int minimumBatchSizeInBytes;
private int currentBatchSizeInBytes;
private int spanStartPosition;
private uint sequenceId;
private bool disposed;
public JaegerExporter(JaegerExporterOptions options)
: this(options, null)
{
}
internal JaegerExporter(JaegerExporterOptions options, TProtocolFactory protocolFactory = null, IJaegerClient client = null)
{
Guard.ThrowIfNull(options);
this.maxPayloadSizeInBytes = (!options.MaxPayloadSizeInBytes.HasValue || options.MaxPayloadSizeInBytes <= 0)
? JaegerExporterOptions.DefaultMaxPayloadSizeInBytes
: options.MaxPayloadSizeInBytes.Value;
if (options.Protocol == JaegerExportProtocol.UdpCompactThrift)
{
protocolFactory ??= new TCompactProtocol.Factory();
client ??= new JaegerUdpClient(options.AgentHost, options.AgentPort);
this.sendUsingEmitBatchArgs = true;
}
else if (options.Protocol == JaegerExportProtocol.HttpBinaryThrift)
{
protocolFactory ??= new TBinaryProtocol.Factory();
client ??= new JaegerHttpClient(
options.Endpoint,
options.HttpClientFactory?.Invoke() ?? throw new InvalidOperationException("JaegerExporterOptions was missing HttpClientFactory or it returned null."));
}
else
{
throw new NotSupportedException();
}
JaegerTagTransformer.LogUnsupportedAttributeType = (string tagValueType, string tagKey) =>
{
JaegerExporterEventSource.Log.UnsupportedAttributeType(tagValueType, tagKey);
};
ConfigurationExtensions.LogInvalidEnvironmentVariable = (string key, string value) =>
{
JaegerExporterEventSource.Log.InvalidEnvironmentVariable(key, value);
};
this.client = client;
this.batchWriter = protocolFactory.GetProtocol(this.maxPayloadSizeInBytes * 2);
this.spanWriter = protocolFactory.GetProtocol(this.maxPayloadSizeInBytes);
this.Process = new();
client.Connect();
}
internal Process Process { get; }
internal EmitBatchArgs EmitBatchArgs { get; private set; }
internal Batch Batch { get; private set; }
/// <inheritdoc/>
public override ExportResult Export(in Batch<Activity> activityBatch)
{
try
{
if (this.Batch == null)
{
this.SetResourceAndInitializeBatch(this.ParentProvider.GetResource());
}
foreach (var activity in activityBatch)
{
var jaegerSpan = activity.ToJaegerSpan();
this.AppendSpan(jaegerSpan);
jaegerSpan.Return();
}
this.SendCurrentBatch();
return ExportResult.Success;
}
catch (Exception ex)
{
JaegerExporterEventSource.Log.FailedExport(ex);
return ExportResult.Failure;
}
}
internal void SetResourceAndInitializeBatch(Resource resource)
{
Guard.ThrowIfNull(resource);
var process = this.Process;
string serviceName = null;
string serviceNamespace = null;
foreach (var label in resource.Attributes)
{
string key = label.Key;
if (label.Value is string strVal)
{
switch (key)
{
case ResourceSemanticConventions.AttributeServiceName:
serviceName = strVal;
continue;
case ResourceSemanticConventions.AttributeServiceNamespace:
serviceNamespace = strVal;
continue;
}
}
if (JaegerTagTransformer.Instance.TryTransformTag(label, out var result))
{
if (process.Tags == null)
{
process.Tags = new Dictionary<string, JaegerTag>();
}
process.Tags[key] = result;
}
}
if (!string.IsNullOrWhiteSpace(serviceName))
{
serviceName = string.IsNullOrEmpty(serviceNamespace)
? serviceName
: serviceNamespace + "." + serviceName;
}
else
{
serviceName = (string)this.ParentProvider.GetDefaultResource().Attributes.FirstOrDefault(
pair => pair.Key == ResourceSemanticConventions.AttributeServiceName).Value;
}
process.ServiceName = serviceName;
this.Batch = new Batch(process, this.batchWriter);
if (this.sendUsingEmitBatchArgs)
{
this.EmitBatchArgs = new EmitBatchArgs(this.batchWriter);
this.Batch.SpanCountPosition += this.EmitBatchArgs.EmitBatchArgsBeginMessage.Length;
this.batchWriter.WriteRaw(this.EmitBatchArgs.EmitBatchArgsBeginMessage);
}
this.batchWriter.WriteRaw(this.Batch.BatchBeginMessage);
this.spanStartPosition = this.batchWriter.Position;
this.minimumBatchSizeInBytes = this.EmitBatchArgs?.MinimumMessageSize ?? 0
+ this.Batch.MinimumMessageSize;
this.ResetBatch();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AppendSpan(JaegerSpan jaegerSpan)
{
jaegerSpan.Write(this.spanWriter);
try
{
var spanTotalBytesNeeded = this.spanWriter.Length;
if (this.NumberOfSpansInCurrentBatch > 0
&& this.currentBatchSizeInBytes + spanTotalBytesNeeded >= this.maxPayloadSizeInBytes)
{
this.SendCurrentBatch();
}
var spanData = this.spanWriter.WrittenData;
this.batchWriter.WriteRaw(spanData);
this.NumberOfSpansInCurrentBatch++;
this.currentBatchSizeInBytes += spanTotalBytesNeeded;
}
finally
{
this.spanWriter.Clear();
}
}
internal void SendCurrentBatch()
{
try
{
this.batchWriter.WriteRaw(this.Batch.BatchEndMessage);
if (this.sendUsingEmitBatchArgs)
{
this.batchWriter.WriteRaw(this.EmitBatchArgs.EmitBatchArgsEndMessage);
this.WriteUInt32AtPosition(this.EmitBatchArgs.SeqIdPosition, ++this.sequenceId);
}
this.WriteUInt32AtPosition(this.Batch.SpanCountPosition, this.NumberOfSpansInCurrentBatch);
var writtenData = this.batchWriter.WrittenData;
this.client.Send(writtenData.Array, writtenData.Offset, writtenData.Count);
}
finally
{
this.ResetBatch();
}
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
try
{
this.client.Close();
}
catch
{
}
this.client.Dispose();
this.batchWriter.Dispose();
this.spanWriter.Dispose();
}
this.disposed = true;
}
base.Dispose(disposing);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteUInt32AtPosition(int position, uint value)
{
this.batchWriter.Position = position;
int numberOfBytes = this.batchWriter.WriteUI32(value, this.uInt32Storage);
this.batchWriter.WriteRaw(this.uInt32Storage, 0, numberOfBytes);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetBatch()
{
this.currentBatchSizeInBytes = this.minimumBatchSizeInBytes;
this.NumberOfSpansInCurrentBatch = 0;
this.batchWriter.Clear(this.spanStartPosition);
}
}

View File

@ -1,136 +0,0 @@
// <copyright file="JaegerExporterHelperExtensions.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;
#if NETFRAMEWORK
using System.Net.Http;
#endif
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenTelemetry.Exporter;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Trace;
/// <summary>
/// Extension methods to simplify registering a Jaeger exporter.
/// </summary>
public static class JaegerExporterHelperExtensions
{
/// <summary>
/// Adds Jaeger exporter to the TracerProvider.
/// </summary>
/// <param name="builder"><see cref="TracerProviderBuilder"/> builder to use.</param>
/// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder builder)
=> AddJaegerExporter(builder, name: null, configure: null);
/// <summary>
/// Adds Jaeger exporter to the TracerProvider.
/// </summary>
/// <param name="builder"><see cref="TracerProviderBuilder"/> builder to use.</param>
/// <param name="configure">Callback action for configuring <see cref="JaegerExporterOptions"/>.</param>
/// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
public static TracerProviderBuilder AddJaegerExporter(this TracerProviderBuilder builder, Action<JaegerExporterOptions> configure)
=> AddJaegerExporter(builder, name: null, configure);
/// <summary>
/// Adds Jaeger exporter to the TracerProvider.
/// </summary>
/// <param name="builder"><see cref="TracerProviderBuilder"/> builder to use.</param>
/// <param name="name">Name which is used when retrieving options.</param>
/// <param name="configure">Callback action for configuring <see cref="JaegerExporterOptions"/>.</param>
/// <returns>The instance of <see cref="TracerProviderBuilder"/> to chain the calls.</returns>
public static TracerProviderBuilder AddJaegerExporter(
this TracerProviderBuilder builder,
string name,
Action<JaegerExporterOptions> configure)
{
Guard.ThrowIfNull(builder);
name ??= Options.DefaultName;
builder.ConfigureServices(services =>
{
if (configure != null)
{
services.Configure(name, configure);
}
services.RegisterOptionsFactory(
(sp, configuration, name) => new JaegerExporterOptions(
configuration,
sp.GetRequiredService<IOptionsMonitor<BatchExportActivityProcessorOptions>>().Get(name)));
});
return builder.AddProcessor(sp =>
{
var options = sp.GetRequiredService<IOptionsMonitor<JaegerExporterOptions>>().Get(name);
return BuildJaegerExporterProcessor(options, sp);
});
}
private static BaseProcessor<Activity> BuildJaegerExporterProcessor(
JaegerExporterOptions options,
IServiceProvider serviceProvider)
{
if (options.Protocol == JaegerExportProtocol.HttpBinaryThrift
&& options.HttpClientFactory == JaegerExporterOptions.DefaultHttpClientFactory)
{
options.HttpClientFactory = () =>
{
Type httpClientFactoryType = Type.GetType("System.Net.Http.IHttpClientFactory, Microsoft.Extensions.Http", throwOnError: false);
if (httpClientFactoryType != null)
{
object httpClientFactory = serviceProvider.GetService(httpClientFactoryType);
if (httpClientFactory != null)
{
MethodInfo createClientMethod = httpClientFactoryType.GetMethod(
"CreateClient",
BindingFlags.Public | BindingFlags.Instance,
binder: null,
new Type[] { typeof(string) },
modifiers: null);
if (createClientMethod != null)
{
return (HttpClient)createClientMethod.Invoke(httpClientFactory, new object[] { "JaegerExporter" });
}
}
}
return new HttpClient();
};
}
var jaegerExporter = new JaegerExporter(options);
if (options.ExportProcessorType == ExportProcessorType.Simple)
{
return new SimpleActivityExportProcessor(jaegerExporter);
}
else
{
return new BatchActivityExportProcessor(
jaegerExporter,
options.BatchExportProcessorOptions.MaxQueueSize,
options.BatchExportProcessorOptions.ScheduledDelayMilliseconds,
options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds,
options.BatchExportProcessorOptions.MaxExportBatchSize);
}
}
}

View File

@ -1,145 +0,0 @@
// <copyright file="JaegerExporterOptions.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;
#if NETFRAMEWORK
using System.Net.Http;
#endif
using Microsoft.Extensions.Configuration;
using OpenTelemetry.Internal;
using OpenTelemetry.Trace;
namespace OpenTelemetry.Exporter;
/// <summary>
/// Jaeger exporter options.
/// OTEL_EXPORTER_JAEGER_AGENT_HOST, OTEL_EXPORTER_JAEGER_AGENT_PORT
/// environment variables are parsed during object construction.
/// </summary>
public class JaegerExporterOptions
{
internal const int DefaultMaxPayloadSizeInBytes = 4096;
internal const string OTelProtocolEnvVarKey = "OTEL_EXPORTER_JAEGER_PROTOCOL";
internal const string OTelAgentHostEnvVarKey = "OTEL_EXPORTER_JAEGER_AGENT_HOST";
internal const string OTelAgentPortEnvVarKey = "OTEL_EXPORTER_JAEGER_AGENT_PORT";
internal const string OTelEndpointEnvVarKey = "OTEL_EXPORTER_JAEGER_ENDPOINT";
internal const string DefaultJaegerEndpoint = "http://localhost:14268/api/traces";
internal static readonly Func<HttpClient> DefaultHttpClientFactory = () => new HttpClient();
/// <summary>
/// Initializes a new instance of the <see cref="JaegerExporterOptions"/> class.
/// </summary>
public JaegerExporterOptions()
: this(new ConfigurationBuilder().AddEnvironmentVariables().Build(), new())
{
}
internal JaegerExporterOptions(
IConfiguration configuration,
BatchExportActivityProcessorOptions defaultBatchOptions)
{
Debug.Assert(configuration != null, "configuration was null");
Debug.Assert(defaultBatchOptions != null, "defaultBatchOptions was null");
if (configuration.TryGetValue<JaegerExportProtocol>(
OTelProtocolEnvVarKey,
JaegerExporterProtocolParser.TryParse,
out var protocol))
{
this.Protocol = protocol;
}
if (configuration.TryGetStringValue(OTelAgentHostEnvVarKey, out var agentHost))
{
this.AgentHost = agentHost;
}
if (configuration.TryGetIntValue(OTelAgentPortEnvVarKey, out var agentPort))
{
this.AgentPort = agentPort;
}
if (configuration.TryGetUriValue(OTelEndpointEnvVarKey, out var endpoint))
{
this.Endpoint = endpoint;
}
this.BatchExportProcessorOptions = defaultBatchOptions;
}
/// <summary>
/// Gets or sets the <see cref="JaegerExportProtocol"/> to use when
/// communicating to Jaeger. Default value: <see
/// cref="JaegerExportProtocol.UdpCompactThrift"/>.
/// </summary>
public JaegerExportProtocol Protocol { get; set; } = JaegerExportProtocol.UdpCompactThrift;
/// <summary>
/// Gets or sets the Jaeger agent host. Default value: localhost.
/// </summary>
public string AgentHost { get; set; } = "localhost";
/// <summary>
/// Gets or sets the Jaeger agent port. Default value: 6831.
/// </summary>
public int AgentPort { get; set; } = 6831;
/// <summary>
/// Gets or sets the Jaeger HTTP endpoint. Default value: "http://localhost:14268/api/traces".
/// Typically https://jaeger-server-name:14268/api/traces.
/// </summary>
public Uri Endpoint { get; set; } = new Uri(DefaultJaegerEndpoint);
/// <summary>
/// Gets or sets the maximum payload size in bytes. Default value: 4096.
/// </summary>
public int? MaxPayloadSizeInBytes { get; set; } = DefaultMaxPayloadSizeInBytes;
/// <summary>
/// Gets or sets the export processor type to be used with Jaeger Exporter. The default value is <see cref="ExportProcessorType.Batch"/>.
/// </summary>
public ExportProcessorType ExportProcessorType { get; set; } = ExportProcessorType.Batch;
/// <summary>
/// Gets or sets the BatchExportProcessor options. Ignored unless ExportProcessorType is BatchExporter.
/// </summary>
public BatchExportProcessorOptions<Activity> BatchExportProcessorOptions { get; set; }
/// <summary>
/// Gets or sets the factory function called to create the <see
/// cref="HttpClient"/> instance that will be used at runtime to
/// transmit spans over HTTP. The returned instance will be reused for
/// all export invocations.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>This is only invoked for the <see
/// cref="JaegerExportProtocol.HttpBinaryThrift"/> protocol.</item>
/// <item>The default behavior when using the <see
/// cref="JaegerExporterHelperExtensions.AddJaegerExporter(TracerProviderBuilder,
/// Action{JaegerExporterOptions})"/> extension is if an <a
/// href="https://docs.microsoft.com/dotnet/api/system.net.http.ihttpclientfactory">IHttpClientFactory</a>
/// instance can be resolved through the application <see
/// cref="IServiceProvider"/> then an <see cref="HttpClient"/> will be
/// created through the factory with the name "JaegerExporter" otherwise
/// an <see cref="HttpClient"/> will be instantiated directly.</item>
/// </list>
/// </remarks>
public Func<HttpClient> HttpClientFactory { get; set; } = DefaultHttpClientFactory;
}

View File

@ -1,36 +0,0 @@
// <copyright file="JaegerExporterProtocolParser.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>
namespace OpenTelemetry.Exporter;
internal static class JaegerExporterProtocolParser
{
public static bool TryParse(string value, out JaegerExportProtocol result)
{
switch (value.Trim().ToLower())
{
case "udp/thrift.compact":
result = JaegerExportProtocol.UdpCompactThrift;
return true;
case "http/thrift.binary":
result = JaegerExportProtocol.HttpBinaryThrift;
return true;
default:
result = default;
return false;
}
}
}

View File

@ -1,43 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>
<Description>Jaeger exporter for OpenTelemetry .NET</Description>
<PackageTags>$(PackageTags);Jaeger;distributed-tracing</PackageTags>
<MinVerTagPrefix>core-</MinVerTagPrefix>
<!-- this is temporary. will remove in future PR. -->
<Nullable>disable</Nullable>
</PropertyGroup>
<PropertyGroup>
<NoWarn>$(NoWarn),1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PooledList.cs" Link="Includes\PooledList.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ResourceSemanticConventions.cs" Link="Includes\ResourceSemanticConventions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ActivityHelperExtensions.cs" Link="Includes\ActivityHelperExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\EnvironmentVariables\*.cs" Link="Includes\EnvironmentVariables\%(Filename).cs" />
<Compile Include="$(RepoRoot)\src\Shared\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\PeerServiceResolver.cs" Link="Includes\PeerServiceResolver.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Options\*.cs" Link="Includes\Options\%(Filename).cs" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\SpanAttributeConstants.cs" Link="Includes\SpanAttributeConstants.cs" />
<Compile Include="$(RepoRoot)\src\Shared\StatusHelper.cs" Link="Includes\StatusHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagTransformer.cs" Link="Includes\TagTransformer.cs" />
<Compile Include="$(RepoRoot)\src\Shared\TagTransformerJsonHelper.cs" Link="Includes\TagTransformerJsonHelper.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Tasks.Extensions" Condition="'$(TargetFramework)' != 'netstandard2.1'" />
<PackageReference Include="System.Text.Encodings.Web" Condition="'$(TargetFramework)' != 'net6.0'" />
<PackageReference Include="System.Text.Json" Condition="'$(TargetFramework)' != 'net6.0'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry\OpenTelemetry.csproj" />
</ItemGroup>
</Project>

View File

@ -1,129 +0,0 @@
# Jaeger Exporter for OpenTelemetry .NET
[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Exporter.Jaeger.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Jaeger)
[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Exporter.Jaeger.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Jaeger)
The Jaeger exporter converts OpenTelemetry traces into the Jaeger model
following the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md).
The exporter communicates to a Jaeger Agent through the Thrift protocol on
the Compact Thrift API port, and as such only supports Thrift over UDP.
> **Note** This component is scheduled to be
> [deprecated](https://github.com/open-telemetry/opentelemetry-specification/pull/2858)
and users are advised to move to [OTLP
Exporter](../OpenTelemetry.Exporter.OpenTelemetryProtocol/README.md). The
[getting started with Jaeger](../../docs/trace/getting-started-jaeger/README.md)
tutorial shows how to use OTLP Exporter to export traces to Jaeger.
## Installation
```shell
dotnet add package OpenTelemetry.Exporter.Jaeger
```
## Configuration
You can configure the `JaegerExporter` through `JaegerExporterOptions`
and environment variables. The `JaegerExporterOptions` setters
take precedence over the environment variables.
## Options Properties
The `JaegerExporter` can be configured using the `JaegerExporterOptions`
properties:
* `AgentHost`: The Jaeger Agent host (default `localhost`). Used for
`UdpCompactThrift` protocol.
* `AgentPort`: The Jaeger Agent port (default `6831`). Used for
`UdpCompactThrift` protocol.
* `BatchExportProcessorOptions`: Configuration options for the batch exporter.
Only used if `ExportProcessorType` is set to `Batch`.
* `Endpoint`: The Jaeger Collector HTTP endpoint (default
`http://localhost:14268`). Used for `HttpBinaryThrift` protocol.
* `ExportProcessorType`: Whether the exporter should use [Batch or Simple
exporting
processor](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#built-in-span-processors)
(default `ExportProcessorType.Batch`).
* `HttpClientFactory`: A factory function called to create the `HttpClient`
instance that will be used at runtime to transmit spans over HTTP when the
`HttpBinaryThrift` protocol is configured. See [Configure
HttpClient](#configure-httpclient) for more details.
* `MaxPayloadSizeInBytes`: The maximum size of each batch that gets sent to the
agent or collector (default `4096`).
* `Protocol`: The protocol to use. The default value is `UdpCompactThrift`.
| Protocol | Description |
|------------------|-------------------------------------------------------|
|`UdpCompactThrift`| Apache Thrift compact over UDP to a Jaeger Agent. |
|`HttpBinaryThrift`| Apache Thrift binary over HTTP to a Jaeger Collector. |
## Environment Variables
The following environment variables can be used to override the default
values of the `JaegerExporterOptions`
(following the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter)).
| Environment variable | `JaegerExporterOptions` property |
|-----------------------------------|-----------------------------------------------------------|
| `OTEL_EXPORTER_JAEGER_AGENT_HOST` | `AgentHost` |
| `OTEL_EXPORTER_JAEGER_AGENT_PORT` | `AgentPort` |
| `OTEL_EXPORTER_JAEGER_ENDPOINT` | `Endpoint` |
| `OTEL_EXPORTER_JAEGER_PROTOCOL` | `Protocol` (`udp/thrift.compact` or `http/thrift.binary`) |
## Configure HttpClient
The `HttpClientFactory` option is provided on `JaegerExporterOptions` for users
who want to configure the `HttpClient` used by the `JaegerExporter` when
`HttpBinaryThrift` protocol is used. Simply replace the function with your own
implementation if you want to customize the generated `HttpClient`:
```csharp
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddJaegerExporter(o =>
{
o.Protocol = JaegerExportProtocol.HttpBinaryThrift;
o.HttpClientFactory = () =>
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value");
return client;
};
}));
```
For users using
[IHttpClientFactory](https://docs.microsoft.com/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests)
you may also customize the named "JaegerExporter" `HttpClient` using the
built-in `AddHttpClient` extension:
```csharp
services.AddHttpClient(
"JaegerExporter",
configureClient: (client) =>
client.DefaultRequestHeaders.Add("X-MyCustomHeader", "value"));
```
Note: The single instance returned by `HttpClientFactory` is reused by all
export requests.
## Troubleshooting
This component uses an
[EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource)
with the name "OpenTelemetry-Exporter-Jaeger" for its internal logging. Please
refer to [SDK troubleshooting](../OpenTelemetry/README.md#troubleshooting) for
instructions on seeing these internal logs.
## References
* [Jaeger](https://www.jaegertracing.io)
* [OpenTelemetry Project](https://opentelemetry.io/)

View File

@ -34,7 +34,6 @@
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry\OpenTelemetry.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.InMemory\OpenTelemetry.Exporter.InMemory.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj" Aliases="Jaeger" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.OpenTelemetryProtocol\OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj" Aliases="OpenTelemetryProtocol" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Zipkin\OpenTelemetry.Exporter.Zipkin.csproj" Aliases="Zipkin" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.Http\OpenTelemetry.Instrumentation.Http.csproj" />

View File

@ -1,90 +0,0 @@
// <copyright file="JaegerExporterBenchmarks.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>
extern alias Jaeger;
using System.Diagnostics;
using BenchmarkDotNet.Attributes;
using Benchmarks.Helper;
using Jaeger::OpenTelemetry.Exporter;
using Jaeger::OpenTelemetry.Exporter.Jaeger.Implementation;
using Jaeger::Thrift.Protocol;
using OpenTelemetry;
using OpenTelemetry.Internal;
namespace Benchmarks.Exporter;
public class JaegerExporterBenchmarks
{
private Activity activity;
private CircularBuffer<Activity> activityBatch;
[Params(1, 10, 100)]
public int NumberOfBatches { get; set; }
[Params(10000)]
public int NumberOfSpans { get; set; }
[GlobalSetup]
public void GlobalSetup()
{
this.activity = ActivityHelper.CreateTestActivity();
this.activityBatch = new CircularBuffer<Activity>(this.NumberOfSpans);
}
[Benchmark]
public void JaegerExporter_Batching()
{
using JaegerExporter exporter = new JaegerExporter(
new JaegerExporterOptions(),
new TCompactProtocol.Factory(),
new NoopJaegerClient());
for (int i = 0; i < this.NumberOfBatches; i++)
{
for (int c = 0; c < this.NumberOfSpans; c++)
{
this.activityBatch.Add(this.activity);
}
exporter.Export(new Batch<Activity>(this.activityBatch, this.NumberOfSpans));
}
exporter.Shutdown();
}
private sealed class NoopJaegerClient : IJaegerClient
{
public bool Connected => true;
public void Close()
{
}
public void Connect()
{
}
public void Dispose()
{
}
public int Send(byte[] buffer, int offset, int count)
{
return count;
}
}
}

View File

@ -17,7 +17,6 @@
<TrimmerRootAssembly Include="OpenTelemetry.Api" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.Console" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.InMemory" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.Jaeger" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.Prometheus.HttpListener" />
<TrimmerRootAssembly Include="OpenTelemetry.Exporter.Zipkin" />

View File

@ -1,30 +0,0 @@
// <copyright file="EventSourceTest.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 OpenTelemetry.Exporter.Jaeger.Implementation;
using OpenTelemetry.Tests;
using Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Tests;
public class EventSourceTest
{
[Fact]
public void EventSourceTest_JaegerExporterEventSource()
{
EventSourceTestHelper.MethodsAreImplementedConsistentlyWithTheirAttributes(JaegerExporterEventSource.Log);
}
}

View File

@ -1,33 +0,0 @@
// <copyright file="Int128Test.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 Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Implementation.Tests;
public class Int128Test
{
[Fact]
public void Int128ConversionWorksAsExpected()
{
var id = ActivityTraceId.CreateFromBytes(new byte[] { 0x1a, 0x0f, 0x54, 0x63, 0x25, 0xa8, 0x56, 0x43, 0x1a, 0x4c, 0x24, 0xea, 0xa8, 0x60, 0xb0, 0xe8 });
var int128 = new Int128(id);
Assert.Equal(unchecked(0x1a0f546325a85643), int128.High);
Assert.Equal(unchecked(0x1a4c24eaa860b0e8), int128.Low);
}
}

View File

@ -1,861 +0,0 @@
// <copyright file="JaegerActivityConversionTest.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 OpenTelemetry.Internal;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Implementation.Tests;
public class JaegerActivityConversionTest
{
static JaegerActivityConversionTest()
{
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
Activity.ForceDefaultIdFormat = true;
var listener = new ActivityListener
{
ShouldListenTo = _ => true,
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
};
ActivitySource.AddActivityListener(listener);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_AllPropertiesSet(bool isRootSpan)
{
using var activity = CreateTestActivity(isRootSpan: isRootSpan);
var traceIdAsInt = new Int128(activity.Context.TraceId);
var spanIdAsInt = new Int128(activity.Context.SpanId);
var linkTraceIdAsInt = new Int128(activity.Links.Single().Context.TraceId);
var linkSpanIdAsInt = new Int128(activity.Links.Single().Context.SpanId);
var jaegerSpan = activity.ToJaegerSpan();
Assert.Equal("Name", jaegerSpan.OperationName);
Assert.Equal(2, jaegerSpan.Logs.Count);
Assert.Equal(traceIdAsInt.High, jaegerSpan.TraceIdHigh);
Assert.Equal(traceIdAsInt.Low, jaegerSpan.TraceIdLow);
Assert.Equal(spanIdAsInt.Low, jaegerSpan.SpanId);
Assert.Equal(new Int128(activity.ParentSpanId).Low, jaegerSpan.ParentSpanId);
Assert.Equal(activity.Links.Count(), jaegerSpan.References.Count);
var references = jaegerSpan.References.ToArray();
var jaegerRef = references[0];
Assert.Equal(linkTraceIdAsInt.High, jaegerRef.TraceIdHigh);
Assert.Equal(linkTraceIdAsInt.Low, jaegerRef.TraceIdLow);
Assert.Equal(linkSpanIdAsInt.Low, jaegerRef.SpanId);
Assert.Equal(0x1, jaegerSpan.Flags);
Assert.Equal(activity.StartTimeUtc.ToEpochMicroseconds(), jaegerSpan.StartTime);
Assert.Equal(TimeSpanToMicroseconds(activity.Duration), jaegerSpan.Duration);
var tags = jaegerSpan.Tags.ToArray();
var tag = tags[0];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("stringKey", tag.Key);
Assert.Equal("value", tag.VStr);
tag = tags[1];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[2];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey2", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[3];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[4];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey2", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[5];
Assert.Equal(JaegerTagType.BOOL, tag.VType);
Assert.Equal("boolKey", tag.Key);
Assert.Equal(true, tag.VBool);
var logs = jaegerSpan.Logs.ToArray();
var jaegerLog = logs[0];
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
Assert.Equal(3, jaegerLog.Fields.Count);
var eventFields = jaegerLog.Fields.ToArray();
var eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[1];
Assert.Equal("string_array", eventField.Key);
Assert.Equal(@"[""a"",""b""]", eventField.VStr);
eventField = eventFields[2];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event1", eventField.VStr);
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
jaegerLog = logs[1];
Assert.Equal(2, jaegerLog.Fields.Count);
eventFields = jaegerLog.Fields.ToArray();
eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[1];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event2", eventField.VStr);
}
[Fact]
public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoAttributes()
{
using var activity = CreateTestActivity(setAttributes: false);
var traceIdAsInt = new Int128(activity.Context.TraceId);
var spanIdAsInt = new Int128(activity.Context.SpanId);
var linkTraceIdAsInt = new Int128(activity.Links.Single().Context.TraceId);
var linkSpanIdAsInt = new Int128(activity.Links.Single().Context.SpanId);
var jaegerSpan = activity.ToJaegerSpan();
Assert.Equal("Name", jaegerSpan.OperationName);
Assert.Equal(2, jaegerSpan.Logs.Count);
Assert.Equal(traceIdAsInt.High, jaegerSpan.TraceIdHigh);
Assert.Equal(traceIdAsInt.Low, jaegerSpan.TraceIdLow);
Assert.Equal(spanIdAsInt.Low, jaegerSpan.SpanId);
Assert.Equal(new Int128(activity.ParentSpanId).Low, jaegerSpan.ParentSpanId);
Assert.Equal(activity.Links.Count(), jaegerSpan.References.Count);
var references = jaegerSpan.References.ToArray();
var jaegerRef = references[0];
Assert.Equal(linkTraceIdAsInt.High, jaegerRef.TraceIdHigh);
Assert.Equal(linkTraceIdAsInt.Low, jaegerRef.TraceIdLow);
Assert.Equal(linkSpanIdAsInt.Low, jaegerRef.SpanId);
Assert.Equal(0x1, jaegerSpan.Flags);
Assert.Equal(activity.StartTimeUtc.ToEpochMicroseconds(), jaegerSpan.StartTime);
Assert.Equal(TimeSpanToMicroseconds(activity.Duration), jaegerSpan.Duration);
// 2 tags: span.kind & library.name.
Assert.Equal(2, jaegerSpan.Tags.Count);
var logs = jaegerSpan.Logs.ToArray();
var jaegerLog = logs[0];
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
Assert.Equal(3, jaegerLog.Fields.Count);
var eventFields = jaegerLog.Fields.ToArray();
var eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[2];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event1", eventField.VStr);
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
jaegerLog = logs[1];
Assert.Equal(2, jaegerLog.Fields.Count);
eventFields = jaegerLog.Fields.ToArray();
eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[1];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event2", eventField.VStr);
}
[Fact]
public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoEvents()
{
using var activity = CreateTestActivity(addEvents: false);
var traceIdAsInt = new Int128(activity.Context.TraceId);
var spanIdAsInt = new Int128(activity.Context.SpanId);
var linkTraceIdAsInt = new Int128(activity.Links.Single().Context.TraceId);
var linkSpanIdAsInt = new Int128(activity.Links.Single().Context.SpanId);
var jaegerSpan = activity.ToJaegerSpan();
Assert.Equal("Name", jaegerSpan.OperationName);
Assert.Empty(jaegerSpan.Logs);
Assert.Equal(traceIdAsInt.High, jaegerSpan.TraceIdHigh);
Assert.Equal(traceIdAsInt.Low, jaegerSpan.TraceIdLow);
Assert.Equal(spanIdAsInt.Low, jaegerSpan.SpanId);
Assert.Equal(new Int128(activity.ParentSpanId).Low, jaegerSpan.ParentSpanId);
Assert.Equal(activity.Links.Count(), jaegerSpan.References.Count);
var references = jaegerSpan.References.ToArray();
var jaegerRef = references[0];
Assert.Equal(linkTraceIdAsInt.High, jaegerRef.TraceIdHigh);
Assert.Equal(linkTraceIdAsInt.Low, jaegerRef.TraceIdLow);
Assert.Equal(linkSpanIdAsInt.Low, jaegerRef.SpanId);
Assert.Equal(0x1, jaegerSpan.Flags);
Assert.Equal(activity.StartTimeUtc.ToEpochMicroseconds(), jaegerSpan.StartTime);
Assert.Equal(TimeSpanToMicroseconds(activity.Duration), jaegerSpan.Duration);
var tags = jaegerSpan.Tags.ToArray();
var tag = tags[0];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("stringKey", tag.Key);
Assert.Equal("value", tag.VStr);
tag = tags[1];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[2];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey2", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[3];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[4];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey2", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[5];
Assert.Equal(JaegerTagType.BOOL, tag.VType);
Assert.Equal("boolKey", tag.Key);
Assert.Equal(true, tag.VBool);
}
[Fact]
public void JaegerActivityConverterTest_ConvertActivityToJaegerSpan_NoLinks()
{
using var activity = CreateTestActivity(addLinks: false, ticksToAdd: 8000);
var traceIdAsInt = new Int128(activity.Context.TraceId);
var spanIdAsInt = new Int128(activity.Context.SpanId);
var jaegerSpan = activity.ToJaegerSpan();
Assert.Equal("Name", jaegerSpan.OperationName);
Assert.Equal(2, jaegerSpan.Logs.Count);
Assert.Equal(traceIdAsInt.High, jaegerSpan.TraceIdHigh);
Assert.Equal(traceIdAsInt.Low, jaegerSpan.TraceIdLow);
Assert.Equal(spanIdAsInt.Low, jaegerSpan.SpanId);
Assert.Equal(new Int128(activity.ParentSpanId).Low, jaegerSpan.ParentSpanId);
Assert.Empty(jaegerSpan.References);
Assert.Equal(0x1, jaegerSpan.Flags);
Assert.Equal(activity.StartTimeUtc.ToEpochMicroseconds(), jaegerSpan.StartTime);
Assert.Equal(TimeSpanToMicroseconds(activity.Duration), jaegerSpan.Duration);
var tags = jaegerSpan.Tags.ToArray();
var tag = tags[0];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("stringKey", tag.Key);
Assert.Equal("value", tag.VStr);
tag = tags[1];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[2];
Assert.Equal(JaegerTagType.LONG, tag.VType);
Assert.Equal("longKey2", tag.Key);
Assert.Equal(1, tag.VLong);
tag = tags[3];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[4];
Assert.Equal(JaegerTagType.DOUBLE, tag.VType);
Assert.Equal("doubleKey2", tag.Key);
Assert.Equal(1, tag.VDouble);
tag = tags[5];
Assert.Equal(JaegerTagType.BOOL, tag.VType);
Assert.Equal("boolKey", tag.Key);
Assert.Equal(true, tag.VBool);
tag = tags[6];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("int_array", tag.Key);
Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1, 2 }), tag.VStr);
tag = tags[7];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("bool_array", tag.Key);
Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { true, false }), tag.VStr);
tag = tags[8];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("double_array", tag.Key);
Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1, 1.1 }), tag.VStr);
tag = tags[9];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("string_array", tag.Key);
Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { "a", "b" }), tag.VStr);
tag = tags[10];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("obj_array", tag.Key);
Assert.Equal(System.Text.Json.JsonSerializer.Serialize(new[] { 1.ToString(), false.ToString(), new object().ToString(), "string", string.Empty, null }), tag.VStr);
// The second to last tag should be span.kind in this case
tag = tags[tags.Length - 2];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("span.kind", tag.Key);
Assert.Equal("client", tag.VStr);
// The last tag should be library.name in this case
tag = tags[tags.Length - 1];
Assert.Equal(JaegerTagType.STRING, tag.VType);
Assert.Equal("otel.library.name", tag.Key);
Assert.Equal(nameof(CreateTestActivity), tag.VStr);
var logs = jaegerSpan.Logs.ToArray();
var jaegerLog = logs[0];
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
Assert.Equal(3, jaegerLog.Fields.Count);
var eventFields = jaegerLog.Fields.ToArray();
var eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[2];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event1", eventField.VStr);
Assert.Equal(activity.Events.First().Timestamp.ToEpochMicroseconds(), jaegerLog.Timestamp);
jaegerLog = logs[1];
Assert.Equal(2, jaegerLog.Fields.Count);
eventFields = jaegerLog.Fields.ToArray();
eventField = eventFields[0];
Assert.Equal("key", eventField.Key);
Assert.Equal("value", eventField.VStr);
eventField = eventFields[1];
Assert.Equal("event", eventField.Key);
Assert.Equal("Event2", eventField.VStr);
}
[Fact]
public void JaegerActivityConverterTest_GenerateJaegerSpan_RemoteEndpointOmittedByDefault()
{
// Arrange
using var span = CreateTestActivity();
// Act
var jaegerSpan = span.ToJaegerSpan();
// Assert
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "peer.service");
}
[Fact]
public void JaegerActivityConverterTest_GenerateJaegerSpan_RemoteEndpointResolution()
{
// Arrange
using var span = CreateTestActivity(
additionalAttributes: new Dictionary<string, object>
{
["net.peer.name"] = "RemoteServiceName",
});
// Act
var jaegerSpan = span.ToJaegerSpan();
// Assert
Assert.Contains(jaegerSpan.Tags, t => t.Key == "peer.service");
Assert.Equal("RemoteServiceName", jaegerSpan.Tags.First(t => t.Key == "peer.service").VStr);
}
[Fact]
public void JaegerActivityConverterTest_GenerateJaegerSpan_PeerServiceNameIgnoredForServerSpan()
{
// Arrange
using var span = CreateTestActivity(
additionalAttributes: new Dictionary<string, object>
{
["http.host"] = "DiscardedRemoteServiceName",
},
kind: ActivityKind.Server);
// Act
var jaegerSpan = span.ToJaegerSpan();
// Assert
Assert.Null(jaegerSpan.PeerServiceName);
Assert.Empty(jaegerSpan.Tags.Where(t => t.Key == "peer.service"));
}
[Theory]
[MemberData(nameof(RemoteEndpointPriorityTestCase.GetTestCases), MemberType = typeof(RemoteEndpointPriorityTestCase))]
public void JaegerActivityConverterTest_GenerateJaegerSpan_RemoteEndpointResolutionPriority(RemoteEndpointPriorityTestCase testCase)
{
// Arrange
using var activity = CreateTestActivity(additionalAttributes: testCase.RemoteEndpointAttributes);
// Act
var jaegerSpan = activity.ToJaegerSpan();
// Assert
var tags = jaegerSpan.Tags.Where(t => t.Key == "peer.service");
Assert.Single(tags);
var tag = tags.First();
Assert.Equal(testCase.ExpectedResult, tag.VStr);
}
[Fact]
public void JaegerActivityConverterTest_NullTagValueTest()
{
// Arrange
using var activity = CreateTestActivity(additionalAttributes: new Dictionary<string, object> { ["nullTag"] = null });
// Act
var jaegerSpan = activity.ToJaegerSpan();
// Assert
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "nullTag");
}
[Theory]
[InlineData(StatusCode.Unset, "unset", "")]
[InlineData(StatusCode.Ok, "Ok", "")]
[InlineData(StatusCode.Error, "ERROR", "error description")]
[InlineData(StatusCode.Unset, "iNvAlId", "")]
public void JaegerActivityConverterTest_Status_ErrorFlagTest(StatusCode expectedStatusCode, string statusCodeTagValue, string statusDescription)
{
// Arrange
using var activity = CreateTestActivity();
activity.SetTag(SpanAttributeConstants.StatusCodeKey, statusCodeTagValue);
activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, statusDescription);
// Act
var jaegerSpan = activity.ToJaegerSpan();
// Assert
Assert.Equal(expectedStatusCode, activity.GetStatus().StatusCode);
if (expectedStatusCode == StatusCode.Unset)
{
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == SpanAttributeConstants.StatusCodeKey);
}
else
{
Assert.Equal(
StatusHelper.GetTagValueForStatusCode(expectedStatusCode),
jaegerSpan.Tags.FirstOrDefault(t => t.Key == SpanAttributeConstants.StatusCodeKey).VStr);
}
if (expectedStatusCode == StatusCode.Error)
{
Assert.Contains(
jaegerSpan.Tags, t =>
t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName &&
t.VType == JaegerTagType.BOOL && (t.VBool ?? false));
Assert.Contains(
jaegerSpan.Tags, t =>
t.Key == SpanAttributeConstants.StatusDescriptionKey &&
t.VType == JaegerTagType.STRING && t.VStr.Equals(statusDescription));
}
else
{
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName);
}
}
[Theory]
[InlineData(ActivityStatusCode.Unset)]
[InlineData(ActivityStatusCode.Ok)]
[InlineData(ActivityStatusCode.Error)]
public void ToJaegerSpan_Activity_Status_And_StatusDescription_is_Set(ActivityStatusCode expectedStatusCode)
{
// Arrange
using var activity = CreateTestActivity();
activity.SetStatus(expectedStatusCode);
// Act
var jaegerSpan = activity.ToJaegerSpan();
// Assert
if (expectedStatusCode == ActivityStatusCode.Unset)
{
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == SpanAttributeConstants.StatusCodeKey);
}
else if (expectedStatusCode == ActivityStatusCode.Ok)
{
Assert.Equal("OK", jaegerSpan.Tags.FirstOrDefault(t => t.Key == SpanAttributeConstants.StatusCodeKey).VStr);
}
// expectedStatusCode is Error
else
{
Assert.Equal("ERROR", jaegerSpan.Tags.FirstOrDefault(t => t.Key == SpanAttributeConstants.StatusCodeKey).VStr);
}
if (expectedStatusCode == ActivityStatusCode.Error)
{
Assert.Contains(
jaegerSpan.Tags, t =>
t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName &&
t.VType == JaegerTagType.BOOL && (t.VBool ?? false));
}
else
{
Assert.DoesNotContain(
jaegerSpan.Tags, t =>
t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName);
}
}
[Fact]
public void ActivityStatus_Takes_precedence_Over_Status_Tags_ActivityStatusCodeIsOk()
{
// Arrange.
using var activity = CreateTestActivity();
const string TagDescriptionOnError = "Description when TagStatusCode is Error.";
activity.SetStatus(ActivityStatusCode.Ok);
activity.SetTag(SpanAttributeConstants.StatusCodeKey, "ERROR");
activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, TagDescriptionOnError);
// Enrich activity with additional tags.
activity.SetTag("myCustomTag", "myCustomTagValue");
// Act.
var jaegerSpan = activity.ToJaegerSpan();
// Assert.
Assert.Equal("OK", jaegerSpan.Tags.FirstOrDefault(t => t.Key == SpanAttributeConstants.StatusCodeKey).VStr);
Assert.Contains(jaegerSpan.Tags, t => t.Key == "otel.status_code" && t.VStr == "OK");
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "otel.status_code" && t.VStr == "ERROR");
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName);
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == SpanAttributeConstants.StatusDescriptionKey &&
t.VType == JaegerTagType.STRING && t.VStr.Equals(TagDescriptionOnError));
// Ensure additional Activity tags were being converted.
Assert.Contains(jaegerSpan.Tags, t => t.Key == "myCustomTag" && t.VStr == "myCustomTagValue");
}
[Fact]
public void ActivityStatus_Takes_precedence_Over_Status_Tags_ActivityStatusCodeIsError()
{
// Arrange.
using var activity = CreateTestActivity();
const string StatusDescriptionOnError = "Description when ActivityStatusCode is Error.";
activity.SetStatus(ActivityStatusCode.Error, StatusDescriptionOnError);
activity.SetTag(SpanAttributeConstants.StatusCodeKey, "OK");
// Enrich activity with additional tags.
activity.SetTag("myCustomTag", "myCustomTagValue");
// Act.
var jaegerSpan = activity.ToJaegerSpan();
// Assert.
Assert.Contains(jaegerSpan.Tags, t => t.Key == "otel.status_code" && t.VStr == "ERROR");
Assert.Contains(jaegerSpan.Tags, t => t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName);
Assert.Contains(jaegerSpan.Tags, t => t.Key == SpanAttributeConstants.StatusDescriptionKey &&
t.VType == JaegerTagType.STRING && t.VStr.Equals(StatusDescriptionOnError));
Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "otel.status_code" && t.VStr == "OK");
// Ensure additional Activity tags were being converted.
Assert.Contains(jaegerSpan.Tags, t => t.Key == "myCustomTag" && t.VStr == "myCustomTagValue");
}
[Fact]
public void ActivityDescription_Takes_precedence_Over_Status_Tags_When_ActivityStatusCodeIsError()
{
// Arrange.
using var activity = CreateTestActivity();
const string StatusDescriptionOnError = "Description when ActivityStatusCode is Error.";
const string TagDescriptionOnError = "Description when TagStatusCode is Error.";
activity.SetStatus(ActivityStatusCode.Error, StatusDescriptionOnError);
activity.SetTag(SpanAttributeConstants.StatusCodeKey, "ERROR");
activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, TagDescriptionOnError);
// Enrich activity with additional tags.
activity.SetTag("myCustomTag", "myCustomTagValue");
// Act.
var jaegerSpan = activity.ToJaegerSpan();
// Assert.
Assert.Equal("ERROR", jaegerSpan.Tags.FirstOrDefault(t => t.Key == SpanAttributeConstants.StatusCodeKey).VStr);
Assert.Contains(
jaegerSpan.Tags, t =>
t.Key == JaegerActivityExtensions.JaegerErrorFlagTagName &&
t.VType == JaegerTagType.BOOL && (t.VBool ?? false));
Assert.Contains(
jaegerSpan.Tags, t =>
t.Key == SpanAttributeConstants.StatusDescriptionKey &&
t.VType == JaegerTagType.STRING && t.VStr.Equals(StatusDescriptionOnError));
// Ensure additional Activity tags were being converted.
Assert.Contains(jaegerSpan.Tags, t => t.Key == "myCustomTag" && t.VStr == "myCustomTagValue");
}
internal static Activity CreateTestActivity(
bool setAttributes = true,
Dictionary<string, object> additionalAttributes = null,
bool addEvents = true,
bool addLinks = true,
Resource resource = null,
ActivityKind kind = ActivityKind.Client,
bool isRootSpan = false,
Status? status = null,
long ticksToAdd = 60 * TimeSpan.TicksPerSecond)
{
var startTimestamp = DateTime.UtcNow;
var endTimestamp = startTimestamp.AddTicks(ticksToAdd);
var eventTimestamp = DateTime.UtcNow;
var traceId = ActivityTraceId.CreateFromString("e8ea7e9ac72de94e91fabc613f9686b2".AsSpan());
var parentSpanId = isRootSpan ? default : ActivitySpanId.CreateFromBytes(new byte[] { 12, 23, 34, 45, 56, 67, 78, 89 });
var attributes = new Dictionary<string, object>
{
{ "exceptionFromToString", new MyToStringMethodThrowsAnException() },
{ "exceptionFromToStringInArray", new MyToStringMethodThrowsAnException[] { new MyToStringMethodThrowsAnException() } },
{ "stringKey", "value" },
{ "longKey", 1L },
{ "longKey2", 1 },
{ "doubleKey", 1D },
{ "doubleKey2", 1F },
{ "boolKey", true },
{ "int_array", new int[] { 1, 2 } },
{ "bool_array", new bool[] { true, false } },
{ "double_array", new double[] { 1.0, 1.1 } },
{ "string_array", new string[] { "a", "b" } },
{ "obj_array", new object[] { 1, false, new object(), "string", string.Empty, null } },
};
if (additionalAttributes != null)
{
foreach (var attribute in additionalAttributes)
{
attributes.Add(attribute.Key, attribute.Value);
}
}
var events = new List<ActivityEvent>
{
new ActivityEvent(
"Event1",
eventTimestamp,
new ActivityTagsCollection(new Dictionary<string, object>
{
{ "key", "value" },
{ "string_array", new string[] { "a", "b" } },
})),
new ActivityEvent(
"Event2",
eventTimestamp,
new ActivityTagsCollection(new Dictionary<string, object>
{
{ "key", "value" },
})),
};
var linkedSpanId = ActivitySpanId.CreateFromString("888915b6286b9c41".AsSpan());
using var activitySource = new ActivitySource(nameof(CreateTestActivity));
var tags = setAttributes ?
attributes
: null;
var links = addLinks ?
new[]
{
new ActivityLink(new ActivityContext(
traceId,
linkedSpanId,
ActivityTraceFlags.Recorded)),
}
: null;
using var activity = activitySource.StartActivity(
"Name",
kind,
parentContext: new ActivityContext(traceId, parentSpanId, ActivityTraceFlags.Recorded),
tags,
links,
startTime: startTimestamp);
if (addEvents)
{
foreach (var evnt in events)
{
activity.AddEvent(evnt);
}
}
if (status.HasValue)
{
activity.SetStatus(status.Value);
}
activity.SetEndTime(endTimestamp);
activity.Stop();
return activity;
}
private static long TimeSpanToMicroseconds(TimeSpan timeSpan)
{
return timeSpan.Ticks / (TimeSpan.TicksPerMillisecond / 1000);
}
public class RemoteEndpointPriorityTestCase
{
public string Name { get; set; }
public string ExpectedResult { get; set; }
public Dictionary<string, object> RemoteEndpointAttributes { get; set; }
public static IEnumerable<object[]> GetTestCases()
{
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Highest priority name = net.peer.name",
ExpectedResult = "RemoteServiceName",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["http.host"] = "DiscardedRemoteServiceName",
["net.peer.name"] = "RemoteServiceName",
["peer.hostname"] = "DiscardedRemoteServiceName",
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Highest priority name = SemanticConventions.AttributePeerService",
ExpectedResult = "RemoteServiceName",
RemoteEndpointAttributes = new Dictionary<string, object>
{
[SemanticConventions.AttributePeerService] = "RemoteServiceName",
["http.host"] = "DiscardedRemoteServiceName",
["net.peer.name"] = "DiscardedRemoteServiceName",
["net.peer.port"] = "1234",
["peer.hostname"] = "DiscardedRemoteServiceName",
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Only has net.peer.name and net.peer.port",
ExpectedResult = "RemoteServiceName:1234",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["net.peer.name"] = "RemoteServiceName",
["net.peer.port"] = "1234",
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "net.peer.port is an int",
ExpectedResult = "RemoteServiceName:1234",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["net.peer.name"] = "RemoteServiceName",
["net.peer.port"] = 1234,
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Has net.peer.name and net.peer.port",
ExpectedResult = "RemoteServiceName:1234",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["http.host"] = "DiscardedRemoteServiceName",
["net.peer.name"] = "RemoteServiceName",
["net.peer.port"] = "1234",
["peer.hostname"] = "DiscardedRemoteServiceName",
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Has net.peer.ip and net.peer.port",
ExpectedResult = "1.2.3.4:1234",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["http.host"] = "DiscardedRemoteServiceName",
["net.peer.ip"] = "1.2.3.4",
["net.peer.port"] = "1234",
["peer.hostname"] = "DiscardedRemoteServiceName",
},
},
};
yield return new object[]
{
new RemoteEndpointPriorityTestCase
{
Name = "Has net.peer.name, net.peer.ip, and net.peer.port",
ExpectedResult = "RemoteServiceName:1234",
RemoteEndpointAttributes = new Dictionary<string, object>
{
["http.host"] = "DiscardedRemoteServiceName",
["net.peer.name"] = "RemoteServiceName",
["net.peer.ip"] = "1.2.3.4",
["net.peer.port"] = "1234",
["peer.hostname"] = "DiscardedRemoteServiceName",
},
},
};
}
public override string ToString()
{
return this.Name;
}
}
private class MyToStringMethodThrowsAnException
{
public override string ToString()
{
throw new Exception("Nope.");
}
}
}

View File

@ -1,156 +0,0 @@
// <copyright file="JaegerExporterOptionsTests.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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenTelemetry.Trace;
using Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Tests;
public class JaegerExporterOptionsTests : IDisposable
{
public JaegerExporterOptionsTests()
{
ClearEnvVars();
}
public void Dispose()
{
ClearEnvVars();
GC.SuppressFinalize(this);
}
[Fact]
public void JaegerExporterOptions_Defaults()
{
var options = new JaegerExporterOptions();
Assert.Equal("localhost", options.AgentHost);
Assert.Equal(6831, options.AgentPort);
Assert.Equal(4096, options.MaxPayloadSizeInBytes);
Assert.Equal(ExportProcessorType.Batch, options.ExportProcessorType);
Assert.Equal(JaegerExportProtocol.UdpCompactThrift, options.Protocol);
Assert.Equal(JaegerExporterOptions.DefaultJaegerEndpoint, options.Endpoint.ToString());
}
[Fact]
public void JaegerExporterOptions_EnvironmentVariableOverride()
{
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, "jaeger-host");
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, "123");
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelProtocolEnvVarKey, "http/thrift.binary");
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelEndpointEnvVarKey, "http://custom-endpoint:12345");
var options = new JaegerExporterOptions();
Assert.Equal("jaeger-host", options.AgentHost);
Assert.Equal(123, options.AgentPort);
Assert.Equal(JaegerExportProtocol.HttpBinaryThrift, options.Protocol);
Assert.Equal(new Uri("http://custom-endpoint:12345"), options.Endpoint);
}
[Fact]
public void JaegerExporterOptions_InvalidEnvironmentVariableOverride()
{
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, "invalid");
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelProtocolEnvVarKey, "invalid");
var options = new JaegerExporterOptions();
Assert.Equal("localhost", options.AgentHost);
Assert.Equal(default(JaegerExportProtocol), options.Protocol);
}
[Fact]
public void JaegerExporterOptions_SetterOverridesEnvironmentVariable()
{
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, "envvar-host");
var options = new JaegerExporterOptions
{
AgentHost = "incode-host",
};
Assert.Equal("incode-host", options.AgentHost);
}
[Fact]
public void JaegerExporterOptions_EnvironmentVariableNames()
{
Assert.Equal("OTEL_EXPORTER_JAEGER_PROTOCOL", JaegerExporterOptions.OTelProtocolEnvVarKey);
Assert.Equal("OTEL_EXPORTER_JAEGER_AGENT_HOST", JaegerExporterOptions.OTelAgentHostEnvVarKey);
Assert.Equal("OTEL_EXPORTER_JAEGER_AGENT_PORT", JaegerExporterOptions.OTelAgentPortEnvVarKey);
Assert.Equal("OTEL_EXPORTER_JAEGER_ENDPOINT", JaegerExporterOptions.OTelEndpointEnvVarKey);
}
[Fact]
public void JaegerExporterOptions_FromConfigurationTest()
{
var values = new Dictionary<string, string>()
{
[JaegerExporterOptions.OTelProtocolEnvVarKey] = "http/thrift.binary",
[JaegerExporterOptions.OTelAgentHostEnvVarKey] = "jaeger-host",
[JaegerExporterOptions.OTelAgentPortEnvVarKey] = "123",
[JaegerExporterOptions.OTelEndpointEnvVarKey] = "http://custom-endpoint:12345",
["OTEL_BSP_MAX_QUEUE_SIZE"] = "18",
["OTEL_BSP_MAX_EXPORT_BATCH_SIZE"] = "2",
["Jaeger:BatchExportProcessorOptions:MaxExportBatchSize"] = "5",
};
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();
IServiceCollection services = null;
using var provider = Sdk.CreateTracerProviderBuilder()
.ConfigureServices(s =>
{
services = s;
services.AddSingleton<IConfiguration>(configuration);
services.Configure<JaegerExporterOptions>(configuration.GetSection("Jaeger"));
})
.AddJaegerExporter()
.Build();
Assert.NotNull(services);
using var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService<IOptionsMonitor<JaegerExporterOptions>>().CurrentValue;
Assert.Equal("jaeger-host", options.AgentHost);
Assert.Equal(123, options.AgentPort);
Assert.Equal(JaegerExportProtocol.HttpBinaryThrift, options.Protocol);
Assert.Equal(new Uri("http://custom-endpoint:12345"), options.Endpoint);
Assert.Equal(18, options.BatchExportProcessorOptions.MaxQueueSize);
// Note:
// 1. OTEL_BSP_MAX_EXPORT_BATCH_SIZE is processed in BatchExportActivityProcessorOptions ctor and sets MaxExportBatchSize to 2.
// 2. Jaeger:BatchExportProcessorOptions:MaxExportBatchSize is processed by options binder after ctor and sets MaxExportBatchSize to 5.
Assert.Equal(5, options.BatchExportProcessorOptions.MaxExportBatchSize);
}
private static void ClearEnvVars()
{
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelProtocolEnvVarKey, null);
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentHostEnvVarKey, null);
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelAgentPortEnvVarKey, null);
Environment.SetEnvironmentVariable(JaegerExporterOptions.OTelEndpointEnvVarKey, null);
}
}

View File

@ -1,34 +0,0 @@
// <copyright file="JaegerExporterProtocolParserTests.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 Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Tests;
public class JaegerExporterProtocolParserTests
{
[Theory]
[InlineData("udp/thrift.compact", true, JaegerExportProtocol.UdpCompactThrift)]
[InlineData("http/thrift.binary", true, JaegerExportProtocol.HttpBinaryThrift)]
[InlineData("unsupported", false, default(JaegerExportProtocol))]
public void TryParse_Protocol_MapsToCorrectValue(string protocol, bool expectedResult, JaegerExportProtocol expectedExportProtocol)
{
var result = JaegerExporterProtocolParser.TryParse(protocol, out var exportProtocol);
Assert.Equal(expectedExportProtocol, exportProtocol);
Assert.Equal(expectedResult, result);
}
}

View File

@ -1,425 +0,0 @@
// <copyright file="JaegerExporterTests.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.Collections.Concurrent;
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Exporter.Jaeger.Implementation;
using OpenTelemetry.Exporter.Jaeger.Implementation.Tests;
using OpenTelemetry.Resources;
using OpenTelemetry.Tests;
using OpenTelemetry.Trace;
using Thrift.Protocol;
using Xunit;
namespace OpenTelemetry.Exporter.Jaeger.Tests;
public class JaegerExporterTests
{
[Fact]
public void AddJaegerExporterNamedOptionsSupported()
{
int defaultExporterOptionsConfigureOptionsInvocations = 0;
int namedExporterOptionsConfigureOptionsInvocations = 0;
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.ConfigureServices(services =>
{
services.Configure<JaegerExporterOptions>(o => defaultExporterOptionsConfigureOptionsInvocations++);
services.Configure<JaegerExporterOptions>("Exporter2", o => namedExporterOptionsConfigureOptionsInvocations++);
})
.AddJaegerExporter()
.AddJaegerExporter("Exporter2", o => { })
.Build();
Assert.Equal(1, defaultExporterOptionsConfigureOptionsInvocations);
Assert.Equal(1, namedExporterOptionsConfigureOptionsInvocations);
}
[Fact]
public void JaegerExporter_BadArgs()
{
TracerProviderBuilder builder = null;
Assert.Throws<ArgumentNullException>(() => builder.AddJaegerExporter());
}
[Fact]
public void JaegerTraceExporter_ctor_NullServiceNameAllowed()
{
using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
Assert.NotNull(jaegerTraceExporter);
}
[Fact]
public void UserHttpFactoryCalled()
{
JaegerExporterOptions options = new JaegerExporterOptions();
var defaultFactory = options.HttpClientFactory;
int invocations = 0;
options.Protocol = JaegerExportProtocol.HttpBinaryThrift;
options.HttpClientFactory = () =>
{
invocations++;
return defaultFactory();
};
using (var exporter = new JaegerExporter(options))
{
Assert.Equal(1, invocations);
}
using (var provider = Sdk.CreateTracerProviderBuilder()
.AddJaegerExporter(o =>
{
o.Protocol = JaegerExportProtocol.HttpBinaryThrift;
o.HttpClientFactory = options.HttpClientFactory;
})
.Build())
{
Assert.Equal(2, invocations);
}
options.HttpClientFactory = null;
Assert.Throws<InvalidOperationException>(() =>
{
using var exporter = new JaegerExporter(options);
});
options.HttpClientFactory = () => null;
Assert.Throws<InvalidOperationException>(() =>
{
using var exporter = new JaegerExporter(options);
});
}
[Fact]
public void ServiceProviderHttpClientFactoryInvoked()
{
IServiceCollection services = new ServiceCollection();
services.AddHttpClient();
int invocations = 0;
services.AddHttpClient("JaegerExporter", configureClient: (client) => invocations++);
services.AddOpenTelemetry().WithTracing(builder => builder
.AddJaegerExporter(o => o.Protocol = JaegerExportProtocol.HttpBinaryThrift));
using var serviceProvider = services.BuildServiceProvider();
var tracerProvider = serviceProvider.GetRequiredService<TracerProvider>();
Assert.Equal(1, invocations);
}
[Theory]
[InlineData("/api/traces")]
[InlineData("/foo/bar")]
[InlineData("/")]
public void HttpClient_Posts_To_Configured_Endpoint(string uriPath)
{
// Arrange
ConcurrentDictionary<Guid, string> responses = new ConcurrentDictionary<Guid, string>();
using var testServer = TestHttpServer.RunServer(
context =>
{
context.Response.StatusCode = 200;
using StreamReader readStream = new StreamReader(context.Request.InputStream);
string requestContent = readStream.ReadToEnd();
responses.TryAdd(
Guid.Parse(context.Request.QueryString["requestId"]),
context.Request.Url.LocalPath);
context.Response.OutputStream.Close();
},
out var testServerHost,
out var testServerPort);
var requestId = Guid.NewGuid();
var options = new JaegerExporterOptions
{
Endpoint = new Uri($"http://{testServerHost}:{testServerPort}{uriPath}?requestId={requestId}"),
Protocol = JaegerExportProtocol.HttpBinaryThrift,
ExportProcessorType = ExportProcessorType.Simple,
};
using var jaegerExporter = new JaegerExporter(options);
// Act
jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);
jaegerExporter.AppendSpan(CreateTestJaegerSpan());
jaegerExporter.SendCurrentBatch();
// Assert
Assert.True(responses.ContainsKey(requestId));
Assert.Equal(uriPath, responses[requestId]);
}
[Fact]
public void JaegerTraceExporter_SetResource_UpdatesServiceName()
{
using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
var process = jaegerTraceExporter.Process;
jaegerTraceExporter.SetResourceAndInitializeBatch(Resource.Empty);
Assert.StartsWith("unknown_service:", process.ServiceName);
jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService").Build());
Assert.Equal("MyService", process.ServiceName);
jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddService("MyService", "MyNamespace").Build());
Assert.Equal("MyNamespace.MyService", process.ServiceName);
}
[Fact]
public void JaegerTraceExporter_SetResource_CreatesTags()
{
using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
var process = jaegerTraceExporter.Process;
jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary<string, object>
{
["Tag"] = "value",
}).Build());
Assert.NotNull(process.Tags);
Assert.Single(process.Tags);
Assert.Equal("value", process.Tags["Tag"].VStr);
}
[Fact]
public void JaegerTraceExporter_SetResource_CombinesTags()
{
using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
var process = jaegerTraceExporter.Process;
JaegerTagTransformer.Instance.TryTransformTag(new KeyValuePair<string, object>("Tag1", "value1"), out var result);
process.Tags = new Dictionary<string, JaegerTag> { ["Tag1"] = result };
jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary<string, object>
{
["Tag2"] = "value2",
}).Build());
Assert.NotNull(process.Tags);
Assert.Equal(2, process.Tags.Count);
Assert.Equal("value1", process.Tags["Tag1"].VStr);
Assert.Equal("value2", process.Tags["Tag2"].VStr);
}
[Fact]
public void JaegerTraceExporter_SetResource_IgnoreServiceResources()
{
using var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
var process = jaegerTraceExporter.Process;
jaegerTraceExporter.SetResourceAndInitializeBatch(ResourceBuilder.CreateEmpty().AddAttributes(new Dictionary<string, object>
{
[ResourceSemanticConventions.AttributeServiceName] = "servicename",
[ResourceSemanticConventions.AttributeServiceNamespace] = "servicenamespace",
}).Build());
Assert.Null(process.Tags);
}
[Fact]
public void JaegerTraceExporter_SetResource_UpdatesServiceNameFromIConfiguration()
{
var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
.ConfigureServices(services =>
{
Dictionary<string, string> configuration = new()
{
["OTEL_SERVICE_NAME"] = "myservicename",
};
services.AddSingleton<IConfiguration>(
new ConfigurationBuilder().AddInMemoryCollection(configuration).Build());
});
var jaegerTraceExporter = new JaegerExporter(new JaegerExporterOptions());
tracerProviderBuilder.AddProcessor(new BatchActivityExportProcessor(jaegerTraceExporter));
using var provider = tracerProviderBuilder.Build();
var process = jaegerTraceExporter.Process;
jaegerTraceExporter.SetResourceAndInitializeBatch(Resource.Empty);
Assert.Equal("myservicename", process.ServiceName);
}
[Fact]
public void JaegerTraceExporter_BuildBatchesToTransmit_FlushedBatch()
{
// Arrange
using var jaegerExporter = new JaegerExporter(new JaegerExporterOptions { MaxPayloadSizeInBytes = 1500 });
jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);
// Act
jaegerExporter.AppendSpan(CreateTestJaegerSpan());
jaegerExporter.AppendSpan(CreateTestJaegerSpan());
jaegerExporter.AppendSpan(CreateTestJaegerSpan());
// Assert
Assert.Equal(1U, jaegerExporter.NumberOfSpansInCurrentBatch);
}
[Theory]
[InlineData("Compact", 1500)]
[InlineData("Binary", 2200)]
public void JaegerTraceExporter_SpansSplitToBatches_SpansIncludedInBatches(string protocolType, int maxPayloadSizeInBytes)
{
TProtocolFactory protocolFactory = protocolType == "Compact"
? new TCompactProtocol.Factory()
: new TBinaryProtocol.Factory();
var client = new TestJaegerClient();
// Arrange
using var jaegerExporter = new JaegerExporter(
new JaegerExporterOptions { MaxPayloadSizeInBytes = maxPayloadSizeInBytes },
protocolFactory,
client);
jaegerExporter.SetResourceAndInitializeBatch(Resource.Empty);
// Create six spans, each taking more space than the previous one
var spans = new JaegerSpan[6];
for (int i = 0; i < 6; i++)
{
spans[i] = CreateTestJaegerSpan(
additionalAttributes: new Dictionary<string, object>
{
["foo"] = new string('_', 10 * i),
});
}
var protocol = protocolFactory.GetProtocol();
var serializedSpans = spans.Select(s =>
{
s.Write(protocol);
var data = protocol.WrittenData.ToArray();
protocol.Clear();
return data;
}).ToArray();
// Act
var sentBatches = new List<byte[]>();
foreach (var span in spans)
{
jaegerExporter.AppendSpan(span);
var sentBatch = client.LastWrittenData;
if (sentBatch != null)
{
sentBatches.Add(sentBatch);
client.LastWrittenData = null;
}
}
// Assert
// Appending the six spans will send two batches with the first four spans
Assert.Equal(2, sentBatches.Count);
Assert.True(
ContainsSequence(sentBatches[0], serializedSpans[0]),
"Expected span data not found in sent batch");
Assert.True(
ContainsSequence(sentBatches[0], serializedSpans[1]),
"Expected span data not found in sent batch");
Assert.True(
ContainsSequence(sentBatches[1], serializedSpans[2]),
"Expected span data not found in sent batch");
Assert.True(
ContainsSequence(sentBatches[1], serializedSpans[3]),
"Expected span data not found in sent batch");
// jaegerExporter.Batch should contain the two remaining spans
Assert.Equal(2U, jaegerExporter.NumberOfSpansInCurrentBatch);
jaegerExporter.SendCurrentBatch();
Assert.True(client.LastWrittenData != null);
var serializedBatch = client.LastWrittenData;
Assert.True(
ContainsSequence(serializedBatch, serializedSpans[4]),
"Expected span data not found in unsent batch");
Assert.True(
ContainsSequence(serializedBatch, serializedSpans[5]),
"Expected span data not found in unsent batch");
}
internal static JaegerSpan CreateTestJaegerSpan(
bool setAttributes = true,
Dictionary<string, object> additionalAttributes = null,
bool addEvents = true,
bool addLinks = true,
Resource resource = null,
ActivityKind kind = ActivityKind.Client)
{
return JaegerActivityConversionTest
.CreateTestActivity(
setAttributes, additionalAttributes, addEvents, addLinks, resource, kind)
.ToJaegerSpan();
}
private static bool ContainsSequence(byte[] source, byte[] pattern)
{
for (var start = 0; start < (source.Length - pattern.Length + 1); start++)
{
if (source.Skip(start).Take(pattern.Length).SequenceEqual(pattern))
{
return true;
}
}
return false;
}
private sealed class TestJaegerClient : IJaegerClient
{
public bool Connected => true;
public byte[] LastWrittenData { get; set; }
public void Close()
{
}
public void Connect()
{
}
public void Dispose()
{
}
public int Send(byte[] buffer, int offset, int count)
{
this.LastWrittenData = new ArraySegment<byte>(buffer, offset, count).ToArray();
return count;
}
}
}

View File

@ -1,33 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Unit test project for Jaeger Exporter for OpenTelemetry</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);net462</TargetFrameworks>
<!-- this is temporary. will remove in future PR. -->
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="All">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Extensions.Hosting\OpenTelemetry.Extensions.Hosting.csproj" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\EventSourceTestHelper.cs" Link="Includes\EventSourceTestHelper.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestActivityProcessor.cs" Link="Includes\TestActivityProcessor.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestEventListener.cs" Link="Includes\TestEventListener.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestHttpServer.cs" Link="Includes\TestHttpServer.cs" />
</ItemGroup>
</Project>