Skip to content

Commit 865520f

Browse files
authored
Feat/opentracing (#1243)
1 parent 3439be8 commit 865520f

File tree

13 files changed

+929
-76
lines changed

13 files changed

+929
-76
lines changed

Ocelot.sln

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "basic", "basic", "{ED066001
8282
EndProject
8383
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "graphql", "graphql", "{C15CD120-5F8D-41DE-9B21-00E3EA77D6C1}"
8484
EndProject
85+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Tracing.OpenTracing", "src\Ocelot.Tracing.OpenTracing\Ocelot.Tracing.OpenTracing.csproj", "{11C622AD-8C0A-4CF4-811B-3DBB76550797}"
86+
EndProject
87+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "open-tracing", "open-tracing", "{731C6A8A-69ED-445C-A132-C638AA93F9C7}"
88+
EndProject
89+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotOpenTracing", "samples\OcelotOpenTracing\OcelotOpenTracing.csproj", "{C9427E78-4281-4F59-A66E-17C0B66550E5}"
90+
EndProject
8591
Global
8692
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8793
Debug|Any CPU = Debug|Any CPU
@@ -180,6 +186,14 @@ Global
180186
{33BE6D88-F188-4E60-83AC-3C4B94D24675}.Debug|Any CPU.Build.0 = Debug|Any CPU
181187
{33BE6D88-F188-4E60-83AC-3C4B94D24675}.Release|Any CPU.ActiveCfg = Release|Any CPU
182188
{33BE6D88-F188-4E60-83AC-3C4B94D24675}.Release|Any CPU.Build.0 = Release|Any CPU
189+
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
190+
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Debug|Any CPU.Build.0 = Debug|Any CPU
191+
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Release|Any CPU.ActiveCfg = Release|Any CPU
192+
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Release|Any CPU.Build.0 = Release|Any CPU
193+
{C9427E78-4281-4F59-A66E-17C0B66550E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
194+
{C9427E78-4281-4F59-A66E-17C0B66550E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
195+
{C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
196+
{C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.Build.0 = Release|Any CPU
183197
EndGlobalSection
184198
GlobalSection(SolutionProperties) = preSolution
185199
HideSolutionNode = FALSE
@@ -214,6 +228,9 @@ Global
214228
{1F1F324D-6EA4-4E63-A6A7-C6053F412F1A} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C}
215229
{ED066001-BAF7-4117-9884-DF591A56347D} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C}
216230
{C15CD120-5F8D-41DE-9B21-00E3EA77D6C1} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C}
231+
{11C622AD-8C0A-4CF4-811B-3DBB76550797} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
232+
{731C6A8A-69ED-445C-A132-C638AA93F9C7} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C}
233+
{C9427E78-4281-4F59-A66E-17C0B66550E5} = {731C6A8A-69ED-445C-A132-C638AA93F9C7}
217234
EndGlobalSection
218235
GlobalSection(ExtensibilityGlobals) = postSolution
219236
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}

docs/features/tracing.rst

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
11
Tracing
22
=======
33

4-
This page details how to perform distributed tracing with Ocelot. At the moment we only support Butterfly but other tracers might just work without
5-
anything Ocelot specific.
4+
This page details how to perform distributed tracing with Ocelot.
5+
6+
OpenTracing
7+
^^^^^^^^^^^
8+
9+
Ocelot providers tracing functionality from the excellent `OpenTracing C# <https://github.com/opentracing/opentracing-csharp>`_ project. The code for the Ocelot integration
10+
can be found `here <https://github.com/ThreeMammals/Ocelot.Tracing.OpenTracing>`_.
11+
12+
The example below uses `Jaeger C# <https://github.com/jaegertracing/jaeger-client-csharp>`_ client to provide the tracer used in Ocelot.
13+
14+
.. code-block:: csharp
15+
16+
services.AddSingleton<ITracer>(sp =>
17+
{
18+
var loggerFactory = sp.GetService<ILoggerFactory>();
19+
Configuration config = new Configuration(context.HostingEnvironment.ApplicationName, loggerFactory);
20+
21+
var tracer = config.GetTracer();
22+
GlobalTracer.Register(tracer);
23+
return tracer;
24+
});
25+
26+
services
27+
.AddOcelot()
28+
.AddOpenTracing();
29+
30+
Then in your ocelot.json add the following to the Route you want to trace..
31+
32+
.. code-block:: json
33+
34+
"HttpHandlerOptions": {
35+
"UseTracing": true
36+
},
37+
38+
Ocelot will now send tracing information to Jaeger when this Route is called.
639

740
Butterfly
841
^^^^^^^^^
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Worker">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Jaeger" Version="0.3.7" />
10+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\..\src\Ocelot.Tracing.OpenTracing\Ocelot.Tracing.OpenTracing.csproj" />
15+
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<Content Update="appsettings.Development.json">
20+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
21+
</Content>
22+
<Content Update="appsettings.json">
23+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
24+
</Content>
25+
<Content Update="ocelot.json">
26+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
27+
</Content>
28+
</ItemGroup>
29+
30+
</Project>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
namespace OcelotOpenTracing
2+
{
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.Hosting;
6+
using System.IO;
7+
using Ocelot.DependencyInjection;
8+
using Ocelot.Middleware;
9+
using Microsoft.Extensions.Logging;
10+
using Ocelot.Tracing.OpenTracing;
11+
using Jaeger;
12+
using Microsoft.Extensions.DependencyInjection;
13+
using OpenTracing;
14+
using OpenTracing.Util;
15+
16+
internal static class Program
17+
{
18+
private static void Main(string[] args)
19+
{
20+
Host.CreateDefaultBuilder()
21+
.ConfigureWebHostDefaults(webBuilder =>
22+
{
23+
webBuilder
24+
.UseContentRoot(Directory.GetCurrentDirectory())
25+
.UseKestrel()
26+
.ConfigureAppConfiguration((hostingContext, config) =>
27+
{
28+
config
29+
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
30+
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
31+
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json",
32+
optional: true, reloadOnChange: false)
33+
.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true)
34+
.AddEnvironmentVariables();
35+
})
36+
.ConfigureServices((context, services) =>
37+
{
38+
services.AddSingleton<ITracer>(sp =>
39+
{
40+
var loggerFactory = sp.GetService<ILoggerFactory>();
41+
Configuration config = new Configuration(context.HostingEnvironment.ApplicationName, loggerFactory);
42+
43+
var tracer = config.GetTracer();
44+
GlobalTracer.Register(tracer);
45+
return tracer;
46+
});
47+
48+
services
49+
.AddOcelot()
50+
.AddOpenTracing();
51+
})
52+
.ConfigureLogging(logging =>
53+
{
54+
logging.AddConsole();
55+
})
56+
.Configure(app =>
57+
{
58+
app.UseOcelot().Wait();
59+
});
60+
})
61+
.Build()
62+
.Run();
63+
}
64+
}
65+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
},
9+
"AllowedHosts": "*"
10+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"ReRoutes": [
3+
{
4+
"HttpHandlerOptions": {
5+
"UseTracing": true
6+
},
7+
"DownstreamPathTemplate": "/todos/{id}",
8+
"DownstreamScheme": "https",
9+
"DownstreamHostAndPorts": [
10+
{
11+
"Host": "jsonplaceholder.typicode.com",
12+
"Port": 443
13+
}
14+
],
15+
"UpstreamPathTemplate": "/posts/{id}",
16+
"UpstreamHttpMethod": [
17+
"Get"
18+
]
19+
}
20+
],
21+
"GlobalConfiguration": {
22+
"BaseUrl": "https://localhost:5000"
23+
}
24+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<Version>0.0.0-dev</Version>
6+
<Authors>Kjell-Åke Gafvelin</Authors>
7+
<Description>This package provides OpenTracing support to Ocelot.</Description>
8+
<PackageProjectUrl>https://github.com/ThreeMammals/Ocelot</PackageProjectUrl>
9+
<PackageTags>API Gateway;.NET core; OpenTracing</PackageTags>
10+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="OpenTracing" Version="0.12.1" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\Ocelot\Ocelot.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Ocelot.Tracing.OpenTracing
2+
{
3+
using Microsoft.Extensions.DependencyInjection.Extensions;
4+
using Ocelot.DependencyInjection;
5+
using Ocelot.Logging;
6+
7+
public static class OcelotBuilderExtensions
8+
{
9+
public static IOcelotBuilder AddOpenTracing(this IOcelotBuilder builder)
10+
{
11+
builder.Services.TryAddSingleton<ITracer, OpenTracingTracer>();
12+
return builder;
13+
}
14+
}
15+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
namespace Ocelot.Tracing.OpenTracing
2+
{
3+
using global::OpenTracing;
4+
using global::OpenTracing.Propagation;
5+
using global::OpenTracing.Tag;
6+
using Microsoft.AspNetCore.Http;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Net.Http;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
13+
class OpenTracingTracer : Logging.ITracer
14+
{
15+
private readonly ITracer _tracer;
16+
17+
public OpenTracingTracer(ITracer tracer)
18+
{
19+
_tracer = tracer ?? throw new ArgumentNullException(nameof(tracer));
20+
}
21+
22+
public void Event(HttpContext httpContext, string @event)
23+
{
24+
}
25+
26+
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
27+
CancellationToken cancellationToken,
28+
Action<string> addTraceIdToRepo,
29+
Func<HttpRequestMessage,
30+
CancellationToken,
31+
Task<HttpResponseMessage>> baseSendAsync)
32+
{
33+
using (IScope scope = _tracer.BuildSpan(request.RequestUri.AbsoluteUri).StartActive(finishSpanOnDispose: true))
34+
{
35+
var span = scope.Span;
36+
37+
span.SetTag(Tags.SpanKind, Tags.SpanKindClient)
38+
.SetTag(Tags.HttpMethod, request.Method.Method)
39+
.SetTag(Tags.HttpUrl, request.RequestUri.OriginalString);
40+
41+
addTraceIdToRepo(span.Context.SpanId);
42+
43+
var headers = new Dictionary<string, string>();
44+
45+
_tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new TextMapInjectAdapter(headers));
46+
47+
foreach (var item in headers)
48+
{
49+
request.Headers.Add(item.Key, item.Value);
50+
}
51+
52+
try
53+
{
54+
var response = await baseSendAsync(request, cancellationToken);
55+
56+
span.SetTag(Tags.HttpStatus, (int)response.StatusCode);
57+
58+
return response;
59+
}
60+
catch (HttpRequestException ex)
61+
{
62+
Tags.Error.Set(scope.Span, true);
63+
64+
span.Log(new Dictionary<string, object>(3)
65+
{
66+
{ LogFields.Event, Tags.Error.Key },
67+
{ LogFields.ErrorKind, ex.GetType().Name },
68+
{ LogFields.ErrorObject, ex }
69+
});
70+
throw;
71+
}
72+
}
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)