mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:15:27 +08:00 
			
		
		
		
	broke out butterfly into seperate project (#521)
* broke out butterfly into seperate project * nearly did it... * updated docs as I have broken the butterfly code off into a seperate dll
This commit is contained in:
		@@ -1,19 +1,29 @@
 | 
				
			|||||||
Tracing
 | 
					Tracing
 | 
				
			||||||
=======
 | 
					=======
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot providers tracing functionality from the excellent `Butterfly <https://github.com/liuhaoyang/butterfly>`_ project. 
 | 
					This page details how to perform distributed tracing with Ocelot. At the moment we only support Butterfly but other tracers might just work without
 | 
				
			||||||
 | 
					anything Ocelot specific.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Butterfly
 | 
				
			||||||
 | 
					^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ocelot providers tracing functionality from the excellent `Butterfly <https://github.com/liuhaoyang/butterfly>`_ project. The code for the Ocelot integration
 | 
				
			||||||
 | 
					can be found `here <https://github.com/ThreeMammals/Ocelot.Tracing.Butterfly>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In order to use the tracing please read the Butterfly documentation.
 | 
					In order to use the tracing please read the Butterfly documentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In ocelot you need to do the following if you wish to trace a ReRoute.
 | 
					In ocelot you need to do the following if you wish to trace a ReRoute.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ``Install-Package Ocelot.Tracing.Butterfly``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
In your ConfigureServices method
 | 
					In your ConfigureServices method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: csharp
 | 
					.. code-block:: csharp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    services
 | 
					    services
 | 
				
			||||||
        .AddOcelot()
 | 
					        .AddOcelot()
 | 
				
			||||||
        .AddOpenTracing(option =>
 | 
					        // this comes from Ocelot.Tracing.Butterfly package
 | 
				
			||||||
 | 
					        .AddButterfly(option =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            //this is the url that the butterfly collector server is running on...
 | 
					            //this is the url that the butterfly collector server is running on...
 | 
				
			||||||
            option.CollectorUrl = "http://localhost:9618";
 | 
					            option.CollectorUrl = "http://localhost:9618";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,17 @@
 | 
				
			|||||||
namespace Ocelot.Configuration.Creator
 | 
					namespace Ocelot.Configuration.Creator
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using System;
 | 
					    using System;
 | 
				
			||||||
    using Butterfly.Client.Tracing;
 | 
					    using Logging;
 | 
				
			||||||
    using Microsoft.Extensions.DependencyInjection;
 | 
					    using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
    using Ocelot.Configuration.File;
 | 
					    using Ocelot.Configuration.File;
 | 
				
			||||||
    using Ocelot.Requester;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
 | 
					    public class HttpHandlerOptionsCreator : IHttpHandlerOptionsCreator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly ITracer _tracer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpHandlerOptionsCreator(IServiceProvider services)
 | 
					        public HttpHandlerOptionsCreator(IServiceProvider services)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tracer = services.GetService<IServiceTracer>();
 | 
					            _tracer = services.GetService<ITracer>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HttpHandlerOptions Create(FileHttpHandlerOptions options)
 | 
					        public HttpHandlerOptions Create(FileHttpHandlerOptions options)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
using Butterfly.Client.AspNetCore;
 | 
					 | 
				
			||||||
using CacheManager.Core;
 | 
					using CacheManager.Core;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
@@ -17,8 +16,6 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
					        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        IOcelotAdministrationBuilder AddAdministration(string path, string secret);
 | 
					        IOcelotAdministrationBuilder AddAdministration(string path, string secret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
 | 
					        IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,10 +40,8 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
    using Ocelot.Configuration;
 | 
					    using Ocelot.Configuration;
 | 
				
			||||||
    using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
					    using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
				
			||||||
    using System.Net.Http;
 | 
					    using System.Net.Http;
 | 
				
			||||||
    using Butterfly.Client.AspNetCore;
 | 
					 | 
				
			||||||
    using Ocelot.Infrastructure;
 | 
					    using Ocelot.Infrastructure;
 | 
				
			||||||
    using Ocelot.Infrastructure.Consul;
 | 
					    using Ocelot.Infrastructure.Consul;
 | 
				
			||||||
    using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
    using Ocelot.Middleware.Multiplexer;
 | 
					    using Ocelot.Middleware.Multiplexer;
 | 
				
			||||||
    using ServiceDiscovery.Providers;
 | 
					    using ServiceDiscovery.Providers;
 | 
				
			||||||
    using Steeltoe.Common.Discovery;
 | 
					    using Steeltoe.Common.Discovery;
 | 
				
			||||||
@@ -228,12 +226,6 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _services.AddButterfly(settings);   
 | 
					 | 
				
			||||||
            return this;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
					        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _services.AddHostedService<FileConfigurationPoller>();
 | 
					            _services.AddHostedService<FileConfigurationPoller>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,26 +2,20 @@
 | 
				
			|||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Microsoft.Extensions.DiagnosticAdapter;
 | 
					using Microsoft.Extensions.DiagnosticAdapter;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Butterfly.Client.AspNetCore;
 | 
					 | 
				
			||||||
using Butterfly.OpenTracing;
 | 
					 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using Ocelot.Infrastructure.Extensions;
 | 
					 | 
				
			||||||
using Ocelot.Requester;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.Logging
 | 
					namespace Ocelot.Logging
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class OcelotDiagnosticListener
 | 
					    public class OcelotDiagnosticListener
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					 | 
				
			||||||
        private readonly IOcelotLogger _logger;
 | 
					        private readonly IOcelotLogger _logger;
 | 
				
			||||||
 | 
					        private readonly ITracer _tracer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OcelotDiagnosticListener(IOcelotLoggerFactory factory, IServiceProvider services)
 | 
					        public OcelotDiagnosticListener(IOcelotLoggerFactory factory, IServiceProvider serviceProvider)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tracer = services.GetService<IServiceTracer>();
 | 
					 | 
				
			||||||
            _logger = factory.CreateLogger<OcelotDiagnosticListener>();
 | 
					            _logger = factory.CreateLogger<OcelotDiagnosticListener>();
 | 
				
			||||||
 | 
					            _tracer = serviceProvider.GetService<ITracer>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [DiagnosticName("Ocelot.MiddlewareException")]
 | 
					        [DiagnosticName("Ocelot.MiddlewareException")]
 | 
				
			||||||
@@ -67,29 +61,7 @@ namespace Ocelot.Logging
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void Event(HttpContext httpContext, string @event)
 | 
					        private void Event(HttpContext httpContext, string @event)
 | 
				
			||||||
        {  
 | 
					        {  
 | 
				
			||||||
            // todo - if the user isnt using tracing the code gets here and will blow up on 
 | 
					            _tracer?.Event(httpContext, @event);
 | 
				
			||||||
            // _tracer.Tracer.TryExtract..
 | 
					 | 
				
			||||||
            if(_tracer == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var span = httpContext.GetSpan();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(span == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var spanBuilder = new SpanBuilder($"server {httpContext.Request.Method} {httpContext.Request.Path}");
 | 
					 | 
				
			||||||
                if (_tracer.Tracer.TryExtract(out var spanContext, httpContext.Request.Headers, (c, k) => c[k].GetValue(),
 | 
					 | 
				
			||||||
                    c => c.Select(x => new KeyValuePair<string, string>(x.Key, x.Value.GetValue())).GetEnumerator()))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    spanBuilder.AsChildOf(spanContext);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                span = _tracer.Start(spanBuilder);        
 | 
					 | 
				
			||||||
                httpContext.SetSpan(span);   
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            span?.Log(LogField.CreateNew().Event(@event));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFramework>netstandard2.0</TargetFramework>
 | 
					    <TargetFramework>netstandard2.0</TargetFramework>
 | 
				
			||||||
    <RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
 | 
					    <RuntimeFrameworkVersion>2.0.0</RuntimeFrameworkVersion>
 | 
				
			||||||
@@ -25,10 +25,6 @@
 | 
				
			|||||||
    <DebugSymbols>True</DebugSymbols>
 | 
					    <DebugSymbols>True</DebugSymbols>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <PackageReference Include="Butterfly.Client" Version="0.0.8" />
 | 
					 | 
				
			||||||
    <PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8">
 | 
					 | 
				
			||||||
      <NoWarn>NU1701</NoWarn>
 | 
					 | 
				
			||||||
    </PackageReference>
 | 
					 | 
				
			||||||
    <PackageReference Include="FluentValidation" Version="7.6.104" />
 | 
					    <PackageReference Include="FluentValidation" Version="7.6.104" />
 | 
				
			||||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.6.0" />
 | 
					    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.6.0" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.1" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.1" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ using System;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.Logging;
 | 
					using Ocelot.Logging;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,19 @@
 | 
				
			|||||||
using System;
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
using System.Net.Http;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
using Butterfly.OpenTracing;
 | 
					 | 
				
			||||||
using Ocelot.Infrastructure.RequestData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Ocelot.Requester
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Logging;
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					    using System.Threading;
 | 
				
			||||||
 | 
					    using System.Threading.Tasks;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
 | 
					    public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly ITracer _tracer;
 | 
				
			||||||
        private readonly IRequestScopedDataRepository _repo;
 | 
					        private readonly IRequestScopedDataRepository _repo;
 | 
				
			||||||
        private const string PrefixSpanId = "ot-spanId";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OcelotHttpTracingHandler(
 | 
					        public OcelotHttpTracingHandler(
 | 
				
			||||||
            IServiceTracer tracer, 
 | 
					            ITracer tracer, 
 | 
				
			||||||
            IRequestScopedDataRepository repo,
 | 
					            IRequestScopedDataRepository repo,
 | 
				
			||||||
            HttpMessageHandler httpMessageHandler = null)
 | 
					            HttpMessageHandler httpMessageHandler = null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -28,46 +26,8 @@ namespace Ocelot.Requester
 | 
				
			|||||||
            HttpRequestMessage request, 
 | 
					            HttpRequestMessage request, 
 | 
				
			||||||
            CancellationToken cancellationToken)
 | 
					            CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return _tracer.ChildTraceAsync($"httpclient {request.Method}", DateTimeOffset.UtcNow, span => TracingSendAsync(span, request, cancellationToken));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        protected virtual async Task<HttpResponseMessage> TracingSendAsync(
 | 
					            return _tracer.SendAsync(request, cancellationToken, x => _repo.Add("TraceId", x), (r,c) => base.SendAsync(r, c));
 | 
				
			||||||
            ISpan span, 
 | 
					 | 
				
			||||||
            HttpRequestMessage request, 
 | 
					 | 
				
			||||||
            CancellationToken cancellationToken)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (request.Headers.Contains(PrefixSpanId))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                request.Headers.Remove(PrefixSpanId);
 | 
					 | 
				
			||||||
                request.Headers.TryAddWithoutValidation(PrefixSpanId, span.SpanContext.SpanId);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _repo.Add("TraceId", span.SpanContext.TraceId);
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            span.Tags.Client().Component("HttpClient")
 | 
					 | 
				
			||||||
                .HttpMethod(request.Method.Method)
 | 
					 | 
				
			||||||
                .HttpUrl(request.RequestUri.OriginalString)
 | 
					 | 
				
			||||||
                .HttpHost(request.RequestUri.Host)
 | 
					 | 
				
			||||||
                .HttpPath(request.RequestUri.PathAndQuery)
 | 
					 | 
				
			||||||
                .PeerAddress(request.RequestUri.OriginalString)
 | 
					 | 
				
			||||||
                .PeerHostName(request.RequestUri.Host)
 | 
					 | 
				
			||||||
                .PeerPort(request.RequestUri.Port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) =>
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (!c.Contains(k))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    c.Add(k, v);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            span.Log(LogField.CreateNew().ClientSend());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var responseMessage = await base.SendAsync(request, cancellationToken);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            span.Log(LogField.CreateNew().ClientReceive());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return responseMessage;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
namespace Ocelot.Requester
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using System;
 | 
					    using System;
 | 
				
			||||||
    using Butterfly.Client.Tracing;
 | 
					    using Logging;
 | 
				
			||||||
    using Ocelot.Infrastructure.RequestData;
 | 
					    using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
    using Microsoft.Extensions.DependencyInjection;
 | 
					    using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class TracingHandlerFactory : ITracingHandlerFactory
 | 
					    public class TracingHandlerFactory : ITracingHandlerFactory
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceTracer _tracer;
 | 
					        private readonly ITracer _tracer;
 | 
				
			||||||
        private readonly IRequestScopedDataRepository _repo;
 | 
					        private readonly IRequestScopedDataRepository _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public TracingHandlerFactory(
 | 
					        public TracingHandlerFactory(
 | 
				
			||||||
@@ -15,7 +15,7 @@ namespace Ocelot.Requester
 | 
				
			|||||||
            IRequestScopedDataRepository repo)
 | 
					            IRequestScopedDataRepository repo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _repo = repo;
 | 
					            _repo = repo;
 | 
				
			||||||
            _tracer = services.GetService<IServiceTracer>();
 | 
					            _tracer = services.GetService<ITracer>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ITracingHandler Get()
 | 
					        public ITracingHandler Get()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,284 +0,0 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.IO;
 | 
					 | 
				
			||||||
using System.Net;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Builder;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					 | 
				
			||||||
using Shouldly;
 | 
					 | 
				
			||||||
using TestStack.BDDfy;
 | 
					 | 
				
			||||||
using Xunit;
 | 
					 | 
				
			||||||
using Butterfly.Client.AspNetCore;
 | 
					 | 
				
			||||||
using static Rafty.Infrastructure.Wait;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Ocelot.AcceptanceTests
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Xunit.Abstractions;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class ButterflyTracingTests : IDisposable
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        private IWebHost _serviceOneBuilder;
 | 
					 | 
				
			||||||
        private IWebHost _serviceTwoBuilder;
 | 
					 | 
				
			||||||
        private IWebHost _fakeButterfly;
 | 
					 | 
				
			||||||
        private readonly Steps _steps;
 | 
					 | 
				
			||||||
        private string _downstreamPathOne;
 | 
					 | 
				
			||||||
        private string _downstreamPathTwo;
 | 
					 | 
				
			||||||
        private int _butterflyCalled;
 | 
					 | 
				
			||||||
        private readonly ITestOutputHelper _output;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public ButterflyTracingTests(ITestOutputHelper output)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _output = output;
 | 
					 | 
				
			||||||
            _steps = new Steps();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Fact]
 | 
					 | 
				
			||||||
        public void should_forward_tracing_information_from_ocelot_and_downstream_services()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var configuration = new FileConfiguration
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ReRoutes = new List<FileReRoute>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        new FileReRoute
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            DownstreamPathTemplate = "/api/values",
 | 
					 | 
				
			||||||
                            DownstreamScheme = "http",
 | 
					 | 
				
			||||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                new FileHostAndPort
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    Host = "localhost",
 | 
					 | 
				
			||||||
                                    Port = 51887,
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            UpstreamPathTemplate = "/api001/values",
 | 
					 | 
				
			||||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
					 | 
				
			||||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                UseTracing = true
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            QoSOptions = new FileQoSOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                ExceptionsAllowedBeforeBreaking = 3,
 | 
					 | 
				
			||||||
                                DurationOfBreak = 10,
 | 
					 | 
				
			||||||
                                TimeoutValue = 5000
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        new FileReRoute
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            DownstreamPathTemplate = "/api/values",
 | 
					 | 
				
			||||||
                            DownstreamScheme = "http",
 | 
					 | 
				
			||||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                new FileHostAndPort
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    Host = "localhost",
 | 
					 | 
				
			||||||
                                    Port = 51388,
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            UpstreamPathTemplate = "/api002/values",
 | 
					 | 
				
			||||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
					 | 
				
			||||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                UseTracing = true
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            QoSOptions = new FileQoSOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                ExceptionsAllowedBeforeBreaking = 3,
 | 
					 | 
				
			||||||
                                DurationOfBreak = 10,
 | 
					 | 
				
			||||||
                                TimeoutValue = 5000
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var butterflyUrl = "http://localhost:9618";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.Given(x => GivenFakeButterfly(butterflyUrl))
 | 
					 | 
				
			||||||
                .And(x => GivenServiceOneIsRunning("http://localhost:51887", "/api/values", 200, "Hello from Laura", butterflyUrl))
 | 
					 | 
				
			||||||
                .And(x => GivenServiceTwoIsRunning("http://localhost:51388", "/api/values", 200, "Hello from Tom", butterflyUrl))
 | 
					 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					 | 
				
			||||||
                .And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
 | 
					 | 
				
			||||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
 | 
					 | 
				
			||||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
					 | 
				
			||||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
					 | 
				
			||||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
 | 
					 | 
				
			||||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
					 | 
				
			||||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
					 | 
				
			||||||
                .BDDfy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var commandOnAllStateMachines = WaitFor(10000).Until(() => _butterflyCalled >= 4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _output.WriteLine($"_butterflyCalled is {_butterflyCalled}");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            commandOnAllStateMachines.ShouldBeTrue();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Fact]
 | 
					 | 
				
			||||||
        public void should_return_tracing_header()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var configuration = new FileConfiguration
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ReRoutes = new List<FileReRoute>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        new FileReRoute
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            DownstreamPathTemplate = "/api/values",
 | 
					 | 
				
			||||||
                            DownstreamScheme = "http",
 | 
					 | 
				
			||||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                new FileHostAndPort
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    Host = "localhost",
 | 
					 | 
				
			||||||
                                    Port = 51387,
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            UpstreamPathTemplate = "/api001/values",
 | 
					 | 
				
			||||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
					 | 
				
			||||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                UseTracing = true
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            QoSOptions = new FileQoSOptions
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                ExceptionsAllowedBeforeBreaking = 3,
 | 
					 | 
				
			||||||
                                DurationOfBreak = 10,
 | 
					 | 
				
			||||||
                                TimeoutValue = 5000
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            DownstreamHeaderTransform = new Dictionary<string, string>()
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                {"Trace-Id", "{TraceId}"},
 | 
					 | 
				
			||||||
                                {"Tom", "Laura"}
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var butterflyUrl = "http://localhost:9618";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.Given(x => GivenFakeButterfly(butterflyUrl))
 | 
					 | 
				
			||||||
                .And(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
 | 
					 | 
				
			||||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
					 | 
				
			||||||
                .And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
 | 
					 | 
				
			||||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
 | 
					 | 
				
			||||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
					 | 
				
			||||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
					 | 
				
			||||||
                .And(x => _steps.ThenTheTraceHeaderIsSet("Trace-Id"))
 | 
					 | 
				
			||||||
                .And(x => _steps.ThenTheResponseHeaderIs("Tom", "Laura"))
 | 
					 | 
				
			||||||
                .BDDfy();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void GivenServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _serviceOneBuilder = new WebHostBuilder()
 | 
					 | 
				
			||||||
                .UseUrls(baseUrl)
 | 
					 | 
				
			||||||
                .UseKestrel()
 | 
					 | 
				
			||||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
					 | 
				
			||||||
                .UseIISIntegration()
 | 
					 | 
				
			||||||
                .ConfigureServices(services => {
 | 
					 | 
				
			||||||
                    services.AddButterfly(option =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        option.CollectorUrl = butterflyUrl;
 | 
					 | 
				
			||||||
                        option.Service = "Service One";
 | 
					 | 
				
			||||||
                        option.IgnoredRoutesRegexPatterns = new string[0];
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Configure(app =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    app.UsePathBase(basePath);
 | 
					 | 
				
			||||||
                    app.Run(async context =>
 | 
					 | 
				
			||||||
                    {   
 | 
					 | 
				
			||||||
                        _downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if(_downstreamPathOne != basePath)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            context.Response.StatusCode = statusCode;
 | 
					 | 
				
			||||||
                            await context.Response.WriteAsync("downstream path didnt match base path");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            context.Response.StatusCode = statusCode;
 | 
					 | 
				
			||||||
                            await context.Response.WriteAsync(responseBody);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Build();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _serviceOneBuilder.Start();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void GivenFakeButterfly(string baseUrl)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _fakeButterfly = new WebHostBuilder()
 | 
					 | 
				
			||||||
                .UseUrls(baseUrl)
 | 
					 | 
				
			||||||
                .UseKestrel()
 | 
					 | 
				
			||||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
					 | 
				
			||||||
                .UseIISIntegration()
 | 
					 | 
				
			||||||
                .Configure(app =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    app.Run(async context =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        _butterflyCalled++;
 | 
					 | 
				
			||||||
                        await context.Response.WriteAsync("OK...");
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Build();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _fakeButterfly.Start();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void GivenServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _serviceTwoBuilder = new WebHostBuilder()
 | 
					 | 
				
			||||||
                .UseUrls(baseUrl)
 | 
					 | 
				
			||||||
                .UseKestrel()
 | 
					 | 
				
			||||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
					 | 
				
			||||||
                .UseIISIntegration()
 | 
					 | 
				
			||||||
                .ConfigureServices(services => {
 | 
					 | 
				
			||||||
                    services.AddButterfly(option =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        option.CollectorUrl = butterflyUrl;
 | 
					 | 
				
			||||||
                        option.Service = "Service Two";
 | 
					 | 
				
			||||||
                        option.IgnoredRoutesRegexPatterns = new string[0];
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Configure(app =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    app.UsePathBase(basePath);
 | 
					 | 
				
			||||||
                    app.Run(async context =>
 | 
					 | 
				
			||||||
                    {   
 | 
					 | 
				
			||||||
                        _downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if(_downstreamPathTwo != basePath)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            context.Response.StatusCode = statusCode;
 | 
					 | 
				
			||||||
                            await context.Response.WriteAsync("downstream path didnt match base path");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            context.Response.StatusCode = statusCode;
 | 
					 | 
				
			||||||
                            await context.Response.WriteAsync(responseBody);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Build();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _serviceTwoBuilder.Start();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPathOne, string expectedDownstreamPath)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _downstreamPathOne.ShouldBe(expectedDownstreamPathOne);
 | 
					 | 
				
			||||||
            _downstreamPathTwo.ShouldBe(expectedDownstreamPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void Dispose()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _serviceOneBuilder?.Dispose();
 | 
					 | 
				
			||||||
            _serviceTwoBuilder?.Dispose();
 | 
					 | 
				
			||||||
            _fakeButterfly?.Dispose();
 | 
					 | 
				
			||||||
            _steps.Dispose();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -31,6 +31,7 @@ using static Ocelot.Infrastructure.Wait;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.AcceptanceTests
 | 
					namespace Ocelot.AcceptanceTests
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Butterfly;
 | 
				
			||||||
    using Configuration.Repository;
 | 
					    using Configuration.Repository;
 | 
				
			||||||
    using Microsoft.Net.Http.Headers;
 | 
					    using Microsoft.Net.Http.Headers;
 | 
				
			||||||
    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
					    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
				
			||||||
@@ -146,44 +147,6 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
					            _ocelotClient = _ocelotServer.CreateClient();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal void GivenOcelotIsRunningUsingButterfly(string butterflyUrl)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _webHostBuilder = new WebHostBuilder();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _webHostBuilder
 | 
					 | 
				
			||||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
					 | 
				
			||||||
                    var env = hostingContext.HostingEnvironment;
 | 
					 | 
				
			||||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
					 | 
				
			||||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
					 | 
				
			||||||
                    config.AddJsonFile("ocelot.json", optional: true, reloadOnChange: false);
 | 
					 | 
				
			||||||
                    config.AddEnvironmentVariables();
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .ConfigureServices(s =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    s.AddOcelot()
 | 
					 | 
				
			||||||
                    .AddOpenTracing(option =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //this is the url that the butterfly collector server is running on...
 | 
					 | 
				
			||||||
                        option.CollectorUrl = butterflyUrl;
 | 
					 | 
				
			||||||
                        option.Service = "Ocelot";
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .Configure(app =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    app.Use(async (context, next) =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        await next.Invoke();
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    app.UseOcelot().Wait();
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal void GivenIWait(int wait)
 | 
					        internal void GivenIWait(int wait)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Thread.Sleep(wait);
 | 
					            Thread.Sleep(wait);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,4 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
using Butterfly.OpenTracing;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Ocelot.Configuration;
 | 
					using Ocelot.Configuration;
 | 
				
			||||||
using Ocelot.Configuration.Creator;
 | 
					using Ocelot.Configuration.Creator;
 | 
				
			||||||
@@ -12,6 +10,12 @@ using Xunit;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.UnitTests.Configuration
 | 
					namespace Ocelot.UnitTests.Configuration
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using System.Net.Http;
 | 
				
			||||||
 | 
					    using System.Threading;
 | 
				
			||||||
 | 
					    using System.Threading.Tasks;
 | 
				
			||||||
 | 
					    using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					    using Ocelot.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class HttpHandlerOptionsCreatorTests
 | 
					    public class HttpHandlerOptionsCreatorTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
 | 
					        private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
 | 
				
			||||||
@@ -155,23 +159,21 @@ namespace Ocelot.UnitTests.Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void GivenARealTracer()
 | 
					        private void GivenARealTracer()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var tracer = new RealTracer();
 | 
					            var tracer = new FakeTracer();
 | 
				
			||||||
            _serviceCollection.AddSingleton<IServiceTracer, RealTracer>();
 | 
					            _serviceCollection.AddSingleton<ITracer, FakeTracer>();
 | 
				
			||||||
            _serviceProvider = _serviceCollection.BuildServiceProvider();
 | 
					            _serviceProvider = _serviceCollection.BuildServiceProvider();
 | 
				
			||||||
            _httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
 | 
					            _httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class RealTracer : IServiceTracer
 | 
					        class FakeTracer : ITracer
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            public ITracer Tracer => throw new NotImplementedException();
 | 
					            public void Event(HttpContext httpContext, string @event)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new NotImplementedException();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public string ServiceName => throw new NotImplementedException();
 | 
					            public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, Action<string> addTraceIdToRepo,
 | 
				
			||||||
 | 
					                Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> baseSendAsync)
 | 
				
			||||||
            public string Environment => throw new NotImplementedException();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            public string Identity => throw new NotImplementedException();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            public ISpan Start(ISpanBuilder spanBuilder)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                throw new NotImplementedException();
 | 
					                throw new NotImplementedException();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,8 @@ using Ocelot.Middleware.Multiplexer;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.UnitTests.DependencyInjection
 | 
					namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Butterfly;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class OcelotBuilderTests
 | 
					    public class OcelotBuilderTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IServiceCollection _services;
 | 
					        private readonly IServiceCollection _services;
 | 
				
			||||||
@@ -140,15 +142,6 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					 | 
				
			||||||
        public void should_set_up_tracing()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
					 | 
				
			||||||
                .When(x => WhenISetUpOpentracing())
 | 
					 | 
				
			||||||
                .When(x => WhenIAccessOcelotHttpTracingHandler())
 | 
					 | 
				
			||||||
                .BDDfy();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_set_up_without_passing_in_config()
 | 
					        public void should_set_up_without_passing_in_config()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -387,24 +380,6 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void WhenISetUpOpentracing()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                _ocelotBuilder.AddOpenTracing(
 | 
					 | 
				
			||||||
                    option =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        option.CollectorUrl = "http://localhost:9618";
 | 
					 | 
				
			||||||
                        option.Service = "Ocelot.ManualTest";
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
               );
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (Exception e)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                _ex = e;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void WhenIAccessLoggerFactory()
 | 
					        private void WhenIAccessLoggerFactory()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,27 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using Butterfly.Client.Tracing;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					 | 
				
			||||||
using Moq;
 | 
					 | 
				
			||||||
using Ocelot.Infrastructure.RequestData;
 | 
					 | 
				
			||||||
using Ocelot.Requester;
 | 
					 | 
				
			||||||
using Shouldly;
 | 
					 | 
				
			||||||
using Xunit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Ocelot.UnitTests.Requester
 | 
					namespace Ocelot.UnitTests.Requester
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					    using Moq;
 | 
				
			||||||
 | 
					    using Ocelot.Infrastructure.RequestData;
 | 
				
			||||||
 | 
					    using Ocelot.Requester;
 | 
				
			||||||
 | 
					    using Shouldly;
 | 
				
			||||||
 | 
					    using Xunit;
 | 
				
			||||||
 | 
					    using Ocelot.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class TracingHandlerFactoryTests
 | 
					    public class TracingHandlerFactoryTests
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private TracingHandlerFactory _factory;
 | 
					        private readonly TracingHandlerFactory _factory;
 | 
				
			||||||
        private Mock<IServiceTracer> _tracer;
 | 
					        private Mock<ITracer> _tracer;
 | 
				
			||||||
        private IServiceCollection _serviceCollection;
 | 
					        private IServiceCollection _serviceCollection;
 | 
				
			||||||
        private IServiceProvider _serviceProvider;
 | 
					        private IServiceProvider _serviceProvider;
 | 
				
			||||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
					        private Mock<IRequestScopedDataRepository> _repo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public TracingHandlerFactoryTests()
 | 
					        public TracingHandlerFactoryTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tracer = new Mock<IServiceTracer>();
 | 
					            _tracer = new Mock<ITracer>();
 | 
				
			||||||
            _serviceCollection = new ServiceCollection();
 | 
					            _serviceCollection = new ServiceCollection();
 | 
				
			||||||
            _serviceCollection.AddSingleton<IServiceTracer>(_tracer.Object);
 | 
					            _serviceCollection.AddSingleton<ITracer>(_tracer.Object);
 | 
				
			||||||
            _serviceProvider = _serviceCollection.BuildServiceProvider();
 | 
					            _serviceProvider = _serviceCollection.BuildServiceProvider();
 | 
				
			||||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
					            _repo = new Mock<IRequestScopedDataRepository>();
 | 
				
			||||||
            _factory = new TracingHandlerFactory(_serviceProvider, _repo.Object);
 | 
					            _factory = new TracingHandlerFactory(_serviceProvider, _repo.Object);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user