From 3c053fb21416f83e68a64bfcbdef898f4f64e789 Mon Sep 17 00:00:00 2001 From: Peter Mounce Date: Fri, 1 Jul 2016 12:16:26 +0100 Subject: [PATCH 1/3] Make it easier to configure Change the `Domain` part of configuration so that it's contextual and sensibly-defaulted Rather than supply the domain at configuration-time, make it possible to set this dynamically according to the traffic that is reaching the endpoints - default it to use the hostname that the traffic is aimed at To retain the previous behaviour, use `(r) => new Uri("some value")` and completely ignore the request context --- README.md | 1 + .../IZipkinConfig.cs | 2 +- .../ZipkinClient.cs | 2 +- .../ZipkinConfig.cs | 4 +- .../ZipkinClientTests.cs | 1048 ++++++++--------- .../ZipkinConfigTests.cs | 18 +- 6 files changed, 530 insertions(+), 545 deletions(-) diff --git a/README.md b/README.md index 0e92b71..a8f443f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ service/environment. - **true**: Disables the ZipkinMiddleware/ZipkinMessageHandler - `ZipkinBaseUri` - is the zipkin scribe/collector server URI with port to send the Spans - `Domain` - is a valid public facing base url for your app instance. Zipkin will use to label the trace. + - by default this looks at the incoming requests and uses the hostname from them. It's a `Func` - customise this to your requirements. - `SpanProcessorBatchSize` - how many Spans should be sent to the zipkin scribe/collector in one go. - `SampleRate` - 1 decimal point float value between 0 and 1. This value will determine randomly if the current request will be traced or not. - `NotToBeDisplayedDomainList`(optional) - It will be used when logging host name by excluding these strings in service name attribute diff --git a/src/Medidata.ZipkinTracer.Core/IZipkinConfig.cs b/src/Medidata.ZipkinTracer.Core/IZipkinConfig.cs index c3b91fa..6f4b17e 100644 --- a/src/Medidata.ZipkinTracer.Core/IZipkinConfig.cs +++ b/src/Medidata.ZipkinTracer.Core/IZipkinConfig.cs @@ -10,7 +10,7 @@ public interface IZipkinConfig Uri ZipkinBaseUri { get; set; } - Uri Domain { get; set; } + Func Domain { get; set; } uint SpanProcessorBatchSize { get; set; } diff --git a/src/Medidata.ZipkinTracer.Core/ZipkinClient.cs b/src/Medidata.ZipkinTracer.Core/ZipkinClient.cs index cd7122c..5cb7a9c 100644 --- a/src/Medidata.ZipkinTracer.Core/ZipkinClient.cs +++ b/src/Medidata.ZipkinTracer.Core/ZipkinClient.cs @@ -43,7 +43,7 @@ public ZipkinClient(IZipkinConfig zipkinConfig, IOwinContext context, SpanCollec spanCollector, new ServiceEndpoint(), zipkinConfig.NotToBeDisplayedDomainList, - zipkinConfig.Domain); + zipkinConfig.Domain(context.Request)); TraceProvider = traceProvider; } diff --git a/src/Medidata.ZipkinTracer.Core/ZipkinConfig.cs b/src/Medidata.ZipkinTracer.Core/ZipkinConfig.cs index fcdf090..ca139a2 100644 --- a/src/Medidata.ZipkinTracer.Core/ZipkinConfig.cs +++ b/src/Medidata.ZipkinTracer.Core/ZipkinConfig.cs @@ -9,7 +9,7 @@ public class ZipkinConfig : IZipkinConfig { public Predicate Bypass { get; set; } = r => false; public Uri ZipkinBaseUri { get; set; } - public Uri Domain { get; set; } + public Func Domain { get; set; } public uint SpanProcessorBatchSize { get; set; } public IList ExcludedPathList { get; set; } = new List(); public double SampleRate { get; set; } @@ -24,7 +24,7 @@ public void Validate() if (Domain == null) { - throw new ArgumentNullException("Domain"); + Domain = request => new Uri(request.Uri.Host); } if (ExcludedPathList == null) diff --git a/tests/Medidata.ZipkinTracer.Core.Test/ZipkinClientTests.cs b/tests/Medidata.ZipkinTracer.Core.Test/ZipkinClientTests.cs index eac510a..0badb92 100644 --- a/tests/Medidata.ZipkinTracer.Core.Test/ZipkinClientTests.cs +++ b/tests/Medidata.ZipkinTracer.Core.Test/ZipkinClientTests.cs @@ -1,516 +1,516 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using Medidata.ZipkinTracer.Core.Logging; +using System.Linq; +using Medidata.ZipkinTracer.Core.Logging; using Medidata.ZipkinTracer.Models; using Microsoft.Owin; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Ploeh.AutoFixture; -using Rhino.Mocks; - -namespace Medidata.ZipkinTracer.Core.Test -{ - [TestClass] - public class ZipkinClientTests - { - private IFixture fixture; - private SpanCollector spanCollectorStub; - private SpanTracer spanTracerStub; - private ITraceProvider traceProvider; - private ILog logger; - private IOwinContext owinContext; - private IDictionary headers; - - [TestInitialize] - public void Init() - { - fixture = new Fixture(); - traceProvider = MockRepository.GenerateStub(); - logger = MockRepository.GenerateStub(); +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Ploeh.AutoFixture; +using Rhino.Mocks; + +namespace Medidata.ZipkinTracer.Core.Test +{ + [TestClass] + public class ZipkinClientTests + { + private IFixture fixture; + private SpanCollector spanCollectorStub; + private SpanTracer spanTracerStub; + private ITraceProvider traceProvider; + private ILog logger; + private IOwinContext owinContext; + private IDictionary headers; + + [TestInitialize] + public void Init() + { + fixture = new Fixture(); + traceProvider = MockRepository.GenerateStub(); + logger = MockRepository.GenerateStub(); owinContext = MockRepository.GenerateStub(); owinContext.Stub(x => x.Environment).Return(new Dictionary()); var request = MockRepository.GenerateStub(); owinContext.Stub(x => x.Request).Return(request); headers = new Dictionary(); request.Stub(x => x.Headers).Return(new HeaderDictionary(headers)); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void CTOR_WithNullConfig() - { - new ZipkinClient(null, owinContext); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void CTOR_WithNullContext() - { - new ZipkinClient(new ZipkinConfig(), null); - } - - [TestMethod] - public void CTOR_WithTraceIdNullOrEmpty() - { + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void CTOR_WithNullConfig() + { + new ZipkinClient(null, owinContext); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void CTOR_WithNullContext() + { + new ZipkinClient(new ZipkinConfig(), null); + } + + [TestMethod] + public void CTOR_WithTraceIdNullOrEmpty() + { + var zipkinConfigStub = CreateZipkinConfigWithDefaultValues(); + + AddTraceId(string.Empty); + AddSampled(false); + + spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); + var zipkinClient = new ZipkinClient(zipkinConfigStub, owinContext, spanCollectorStub); + Assert.IsFalse(zipkinClient.IsTraceOn); + } + + [TestMethod] + public void CTOR_WithIsSampledFalse() + { var zipkinConfigStub = CreateZipkinConfigWithDefaultValues(); - AddTraceId(string.Empty); - AddSampled(false); - - spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); - var zipkinClient = new ZipkinClient(zipkinConfigStub, owinContext, spanCollectorStub); - Assert.IsFalse(zipkinClient.IsTraceOn); - } - - [TestMethod] - public void CTOR_WithIsSampledFalse() - { - var zipkinConfigStub = CreateZipkinConfigWithDefaultValues(); - - AddTraceId(fixture.Create()); - AddSampled(false); - - spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); - var zipkinClient = new ZipkinClient(zipkinConfigStub, owinContext, spanCollectorStub); - Assert.IsFalse(zipkinClient.IsTraceOn); - } - - [TestMethod] - public void CTOR_StartCollector() - { - var zipkinClient = (ZipkinClient)SetupZipkinClient(); - Assert.IsNotNull(zipkinClient.spanCollector); - Assert.IsNotNull(zipkinClient.spanTracer); - } - - [TestMethod] - public void Shutdown_StopCollector() - { - var zipkinClient = (ZipkinClient)SetupZipkinClient(); - - zipkinClient.ShutDown(); - - spanCollectorStub.AssertWasCalled(x => x.Stop()); - } - - [TestMethod] - public void Shutdown_CollectorNullDoesntThrow() - { - var zipkinClient = (ZipkinClient)SetupZipkinClient(); - zipkinClient.spanCollector = null; - - zipkinClient.ShutDown(); - } - - [TestMethod] - public void StartServerSpan() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var uriHost = "https://www.x@y.com"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - var requestUri = new Uri(uriHost + uriAbsolutePath); - - var expectedSpan = new Span(); - spanTracerStub.Expect( - x => x.ReceiveServerSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Equal(traceProvider.TraceId), - Arg.Is.Equal(traceProvider.ParentSpanId), - Arg.Is.Equal(traceProvider.SpanId), - Arg.Is.Equal(requestUri))).Return(expectedSpan); - - var result = tracerClient.StartServerTrace(requestUri, methodName); - - Assert.AreEqual(expectedSpan, result); - } - - [TestMethod] - public void StartServerSpan_Exception() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var uriHost = "https://www.x@y.com"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - var requestUri = new Uri(uriHost + uriAbsolutePath); - - spanTracerStub.Expect( - x => x.ReceiveServerSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Anything, - Arg.Is.Anything, - Arg.Is.Anything, - Arg.Is.Equal(requestUri))).Throw(new Exception()); - - var result = tracerClient.StartServerTrace(requestUri, methodName); - - Assert.IsNull(result); - } - - [TestMethod] - public void StartServerSpan_IsTraceOnIsFalse() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - var uriHost = "https://www.x@y.com"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - - var result = tracerClient.StartServerTrace(new Uri(uriHost + uriAbsolutePath), methodName); - - Assert.IsNull(result); - } - - [TestMethod] - public void EndServerSpan() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var serverSpan = new Span(); - - tracerClient.EndServerTrace(serverSpan); - - spanTracerStub.AssertWasCalled(x => x.SendServerSpan(serverSpan)); - } - - [TestMethod] - public void EndServerSpan_Exception() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var serverSpan = new Span(); - - spanTracerStub.Expect(x => x.SendServerSpan(serverSpan)).Throw(new Exception()); - - tracerClient.EndServerTrace(serverSpan); - } - - [TestMethod] - public void EndServerSpan_IsTraceOnIsFalse_DoesntThrow() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - var serverSpan = new Span(); - - tracerClient.EndServerTrace(serverSpan); - } - - [TestMethod] - public void EndServerSpan_NullServerSpan_DoesntThrow() - { - var tracerClient = SetupZipkinClient(); - - tracerClient.EndServerTrace(null); - } - - [TestMethod] - public void StartClientSpan() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientServiceName = "abc-sandbox"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - - var expectedSpan = new Span(); - spanTracerStub.Expect( - x => x.SendClientSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Equal(traceProvider.TraceId), - Arg.Is.Equal(traceProvider.ParentSpanId), - Arg.Is.Equal(traceProvider.SpanId), - Arg.Is.Anything)).Return(expectedSpan); - - var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); - - Assert.AreEqual(expectedSpan, result); - } - - [TestMethod] - public void StartClientSpan_UsingIpAddress() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientServiceName = "192.168.178.178"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - - var expectedSpan = new Span(); - spanTracerStub.Expect( - x => x.SendClientSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Equal(traceProvider.TraceId), - Arg.Is.Equal(traceProvider.ParentSpanId), - Arg.Is.Equal(traceProvider.SpanId), - Arg.Is.Anything)).Return(expectedSpan); - - var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); - - Assert.AreEqual(expectedSpan, result); - } - - [TestMethod] - public void StartClientSpan_MultipleDomainList() - { - var zipkinConfig = CreateZipkinConfigWithDefaultValues(); - zipkinConfig.NotToBeDisplayedDomainList = new List { ".abc.net", ".xyz.net" }; - var tracerClient = SetupZipkinClient(zipkinConfig); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientServiceName = "abc-sandbox"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - - var expectedSpan = new Span(); - spanTracerStub.Expect( - x => x.SendClientSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Equal(traceProvider.TraceId), - Arg.Is.Equal(traceProvider.ParentSpanId), - Arg.Is.Equal(traceProvider.SpanId), - Arg.Is.Anything)).Return(expectedSpan); - - var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); - - Assert.AreEqual(expectedSpan, result); - } - - [TestMethod] - public void StartClientSpan_Exception() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientServiceName = "abc-sandbox"; - var uriAbsolutePath = "/object"; - var methodName = "GET"; - var spanName = methodName; - - spanTracerStub.Expect( - x => x.SendClientSpan( - Arg.Is.Equal(spanName.ToLower()), - Arg.Is.Anything, - Arg.Is.Anything, - Arg.Is.Anything, - Arg.Is.Anything)).Throw(new Exception()); - - var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); - - Assert.IsNull(result); - } - - [TestMethod] - public void StartClientSpan_IsTraceOnIsFalse() - { - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - var clientServiceName = "abc-sandbox"; - var clientServiceUri = new Uri("https://" + clientServiceName + ".xyz.net:8000"); - var methodName = "GET"; - - var result = tracerClient.StartClientTrace(clientServiceUri, methodName, traceProvider); - - Assert.IsNull(result); - } - - [TestMethod] - public void EndClientSpan() - { - var returnCode = fixture.Create(); - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientSpan = new Span(); - - tracerClient.EndClientTrace(clientSpan, returnCode); - - spanTracerStub.AssertWasCalled(x => x.ReceiveClientSpan(clientSpan, returnCode)); - } - - [TestMethod] - public void EndClientSpan_Exception() - { - var returnCode = fixture.Create(); - var tracerClient = SetupZipkinClient(); - var zipkinClient = (ZipkinClient)tracerClient; - spanTracerStub = GetSpanTracerStub(); - zipkinClient.spanTracer = spanTracerStub; - var clientSpan = new Span(); - - spanTracerStub.Expect(x => x.ReceiveClientSpan(clientSpan, returnCode)).Throw(new Exception()); - - tracerClient.EndClientTrace(clientSpan, returnCode); - } - - [TestMethod] - public void EndClientSpan_NullClientTrace_DoesntThrow() - { - var returnCode = fixture.Create(); - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - - var called = false; - spanTracerStub.Stub(x => x.ReceiveClientSpan(Arg.Is.Anything, Arg.Is.Equal(returnCode))) - .WhenCalled(x => { called = true; }); - - tracerClient.EndClientTrace(null, returnCode); - - Assert.IsFalse(called); - } - - [TestMethod] - public void EndClientSpan_IsTraceOnIsFalse_DoesntThrow() - { - var returnCode = fixture.Create(); - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - - var called = false; - spanTracerStub.Stub(x => x.ReceiveClientSpan(Arg.Is.Anything, Arg.Is.Equal(returnCode))) - .WhenCalled(x => { called = true; }); - - tracerClient.EndClientTrace(new Span(), returnCode); - - Assert.IsFalse(called); - } - - [TestMethod] - [TestCategory("TraceRecordTests")] - public void Record_IsTraceOnIsFalse_DoesNotAddAnnotation() - { - // Arrange - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - - var testSpan = new Span(); - - // Act - tracerClient.Record(testSpan, "irrelevant"); - - // Assert - Assert.IsFalse(testSpan.Annotations.Any(), "There are annotations but the trace is off."); - } - - [TestMethod] - [TestCategory("TraceRecordTests")] - public void Record_WithoutValue_AddsAnnotationWithCallerName() - { - // Arrange - var callerMemberName = new StackTrace().GetFrame(0).GetMethod().Name; - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = true; - - var testSpan = new Span(); - - // Act - tracerClient.Record(testSpan); - - // Assert - Assert.AreEqual(1, testSpan.Annotations.Count, "There is not exactly one annotation added."); - Assert.IsNotNull( - testSpan.GetAnnotationsByType().SingleOrDefault(a => (string)a.Value == callerMemberName), - "The record with the caller name is not found in the Annotations." - ); - } - - [TestMethod] - [TestCategory("TraceRecordTests")] - public void RecordBinary_IsTraceOnIsFalse_DoesNotAddBinaryAnnotation() - { - // Arrange - var keyName = "TestKey"; - var testValue = "Some Value"; - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - - var testSpan = new Span(); - - // Act - tracerClient.RecordBinary(testSpan, keyName, testValue); - - // Assert - Assert.IsFalse(testSpan.GetAnnotationsByType().Any(), "There are annotations but the trace is off."); - } - - [TestMethod] - [TestCategory("TraceRecordTests")] - public void RecordLocalComponent_WithNotNullValue_AddsLocalComponentAnnotation() - { - // Arrange - var testValue = "Some Value"; - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = true; - - var testSpan = new Span(); - - // Act - tracerClient.RecordLocalComponent(testSpan, testValue); - - // Assert - var annotation = testSpan.GetAnnotationsByType().SingleOrDefault(a => a.Key == ZipkinConstants.LocalComponent); - Assert.IsNotNull(annotation, "There is no local trace annotation in the binary annotations."); - Assert.AreEqual(testValue, annotation.Value, "The local component annotation value is not correct."); - } - - [TestMethod] - [TestCategory("TraceRecordTests")] - public void RecordLocalComponent_IsTraceOnIsFalse_DoesNotAddLocalComponentAnnotation() - { - // Arrange - var testValue = "Some Value"; - var tracerClient = SetupZipkinClient(); - spanTracerStub = GetSpanTracerStub(); - var zipkinClient = (ZipkinClient)tracerClient; - zipkinClient.IsTraceOn = false; - - var testSpan = new Span(); - - // Act - tracerClient.RecordBinary(testSpan, ZipkinConstants.LocalComponent, testValue); - - // Assert - Assert.IsFalse(testSpan.GetAnnotationsByType().Any(), "There are annotations but the trace is off."); - } - - private ITracerClient SetupZipkinClient(IZipkinConfig zipkinConfig = null) - { - spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); + AddTraceId(fixture.Create()); + AddSampled(false); + + spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); + var zipkinClient = new ZipkinClient(zipkinConfigStub, owinContext, spanCollectorStub); + Assert.IsFalse(zipkinClient.IsTraceOn); + } + + [TestMethod] + public void CTOR_StartCollector() + { + var zipkinClient = (ZipkinClient)SetupZipkinClient(); + Assert.IsNotNull(zipkinClient.spanCollector); + Assert.IsNotNull(zipkinClient.spanTracer); + } + + [TestMethod] + public void Shutdown_StopCollector() + { + var zipkinClient = (ZipkinClient)SetupZipkinClient(); + + zipkinClient.ShutDown(); + + spanCollectorStub.AssertWasCalled(x => x.Stop()); + } + + [TestMethod] + public void Shutdown_CollectorNullDoesntThrow() + { + var zipkinClient = (ZipkinClient)SetupZipkinClient(); + zipkinClient.spanCollector = null; + + zipkinClient.ShutDown(); + } + + [TestMethod] + public void StartServerSpan() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var uriHost = "https://www.x@y.com"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + var requestUri = new Uri(uriHost + uriAbsolutePath); + + var expectedSpan = new Span(); + spanTracerStub.Expect( + x => x.ReceiveServerSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Equal(traceProvider.TraceId), + Arg.Is.Equal(traceProvider.ParentSpanId), + Arg.Is.Equal(traceProvider.SpanId), + Arg.Is.Equal(requestUri))).Return(expectedSpan); + + var result = tracerClient.StartServerTrace(requestUri, methodName); + + Assert.AreEqual(expectedSpan, result); + } + + [TestMethod] + public void StartServerSpan_Exception() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var uriHost = "https://www.x@y.com"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + var requestUri = new Uri(uriHost + uriAbsolutePath); + + spanTracerStub.Expect( + x => x.ReceiveServerSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Anything, + Arg.Is.Anything, + Arg.Is.Anything, + Arg.Is.Equal(requestUri))).Throw(new Exception()); + + var result = tracerClient.StartServerTrace(requestUri, methodName); + + Assert.IsNull(result); + } + + [TestMethod] + public void StartServerSpan_IsTraceOnIsFalse() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + var uriHost = "https://www.x@y.com"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + + var result = tracerClient.StartServerTrace(new Uri(uriHost + uriAbsolutePath), methodName); + + Assert.IsNull(result); + } + + [TestMethod] + public void EndServerSpan() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var serverSpan = new Span(); + + tracerClient.EndServerTrace(serverSpan); + + spanTracerStub.AssertWasCalled(x => x.SendServerSpan(serverSpan)); + } + + [TestMethod] + public void EndServerSpan_Exception() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var serverSpan = new Span(); + + spanTracerStub.Expect(x => x.SendServerSpan(serverSpan)).Throw(new Exception()); + + tracerClient.EndServerTrace(serverSpan); + } + + [TestMethod] + public void EndServerSpan_IsTraceOnIsFalse_DoesntThrow() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + var serverSpan = new Span(); + + tracerClient.EndServerTrace(serverSpan); + } + + [TestMethod] + public void EndServerSpan_NullServerSpan_DoesntThrow() + { + var tracerClient = SetupZipkinClient(); + + tracerClient.EndServerTrace(null); + } + + [TestMethod] + public void StartClientSpan() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientServiceName = "abc-sandbox"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + + var expectedSpan = new Span(); + spanTracerStub.Expect( + x => x.SendClientSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Equal(traceProvider.TraceId), + Arg.Is.Equal(traceProvider.ParentSpanId), + Arg.Is.Equal(traceProvider.SpanId), + Arg.Is.Anything)).Return(expectedSpan); + + var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); + + Assert.AreEqual(expectedSpan, result); + } + + [TestMethod] + public void StartClientSpan_UsingIpAddress() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientServiceName = "192.168.178.178"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + + var expectedSpan = new Span(); + spanTracerStub.Expect( + x => x.SendClientSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Equal(traceProvider.TraceId), + Arg.Is.Equal(traceProvider.ParentSpanId), + Arg.Is.Equal(traceProvider.SpanId), + Arg.Is.Anything)).Return(expectedSpan); + + var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); + + Assert.AreEqual(expectedSpan, result); + } + + [TestMethod] + public void StartClientSpan_MultipleDomainList() + { + var zipkinConfig = CreateZipkinConfigWithDefaultValues(); + zipkinConfig.NotToBeDisplayedDomainList = new List { ".abc.net", ".xyz.net" }; + var tracerClient = SetupZipkinClient(zipkinConfig); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientServiceName = "abc-sandbox"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + + var expectedSpan = new Span(); + spanTracerStub.Expect( + x => x.SendClientSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Equal(traceProvider.TraceId), + Arg.Is.Equal(traceProvider.ParentSpanId), + Arg.Is.Equal(traceProvider.SpanId), + Arg.Is.Anything)).Return(expectedSpan); + + var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); + + Assert.AreEqual(expectedSpan, result); + } + + [TestMethod] + public void StartClientSpan_Exception() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientServiceName = "abc-sandbox"; + var uriAbsolutePath = "/object"; + var methodName = "GET"; + var spanName = methodName; + + spanTracerStub.Expect( + x => x.SendClientSpan( + Arg.Is.Equal(spanName.ToLower()), + Arg.Is.Anything, + Arg.Is.Anything, + Arg.Is.Anything, + Arg.Is.Anything)).Throw(new Exception()); + + var result = tracerClient.StartClientTrace(new Uri("https://" + clientServiceName + ".xyz.net:8000" + uriAbsolutePath), methodName, traceProvider); + + Assert.IsNull(result); + } + + [TestMethod] + public void StartClientSpan_IsTraceOnIsFalse() + { + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + var clientServiceName = "abc-sandbox"; + var clientServiceUri = new Uri("https://" + clientServiceName + ".xyz.net:8000"); + var methodName = "GET"; + + var result = tracerClient.StartClientTrace(clientServiceUri, methodName, traceProvider); + + Assert.IsNull(result); + } + + [TestMethod] + public void EndClientSpan() + { + var returnCode = fixture.Create(); + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientSpan = new Span(); + + tracerClient.EndClientTrace(clientSpan, returnCode); + + spanTracerStub.AssertWasCalled(x => x.ReceiveClientSpan(clientSpan, returnCode)); + } + + [TestMethod] + public void EndClientSpan_Exception() + { + var returnCode = fixture.Create(); + var tracerClient = SetupZipkinClient(); + var zipkinClient = (ZipkinClient)tracerClient; + spanTracerStub = GetSpanTracerStub(); + zipkinClient.spanTracer = spanTracerStub; + var clientSpan = new Span(); + + spanTracerStub.Expect(x => x.ReceiveClientSpan(clientSpan, returnCode)).Throw(new Exception()); + + tracerClient.EndClientTrace(clientSpan, returnCode); + } + + [TestMethod] + public void EndClientSpan_NullClientTrace_DoesntThrow() + { + var returnCode = fixture.Create(); + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + + var called = false; + spanTracerStub.Stub(x => x.ReceiveClientSpan(Arg.Is.Anything, Arg.Is.Equal(returnCode))) + .WhenCalled(x => { called = true; }); + + tracerClient.EndClientTrace(null, returnCode); + + Assert.IsFalse(called); + } + + [TestMethod] + public void EndClientSpan_IsTraceOnIsFalse_DoesntThrow() + { + var returnCode = fixture.Create(); + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + + var called = false; + spanTracerStub.Stub(x => x.ReceiveClientSpan(Arg.Is.Anything, Arg.Is.Equal(returnCode))) + .WhenCalled(x => { called = true; }); + + tracerClient.EndClientTrace(new Span(), returnCode); + + Assert.IsFalse(called); + } + + [TestMethod] + [TestCategory("TraceRecordTests")] + public void Record_IsTraceOnIsFalse_DoesNotAddAnnotation() + { + // Arrange + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + + var testSpan = new Span(); + + // Act + tracerClient.Record(testSpan, "irrelevant"); + + // Assert + Assert.IsFalse(testSpan.Annotations.Any(), "There are annotations but the trace is off."); + } + + [TestMethod] + [TestCategory("TraceRecordTests")] + public void Record_WithoutValue_AddsAnnotationWithCallerName() + { + // Arrange + var callerMemberName = new StackTrace().GetFrame(0).GetMethod().Name; + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = true; + + var testSpan = new Span(); + + // Act + tracerClient.Record(testSpan); + + // Assert + Assert.AreEqual(1, testSpan.Annotations.Count, "There is not exactly one annotation added."); + Assert.IsNotNull( + testSpan.GetAnnotationsByType().SingleOrDefault(a => (string)a.Value == callerMemberName), + "The record with the caller name is not found in the Annotations." + ); + } + + [TestMethod] + [TestCategory("TraceRecordTests")] + public void RecordBinary_IsTraceOnIsFalse_DoesNotAddBinaryAnnotation() + { + // Arrange + var keyName = "TestKey"; + var testValue = "Some Value"; + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + + var testSpan = new Span(); + + // Act + tracerClient.RecordBinary(testSpan, keyName, testValue); + + // Assert + Assert.IsFalse(testSpan.GetAnnotationsByType().Any(), "There are annotations but the trace is off."); + } + + [TestMethod] + [TestCategory("TraceRecordTests")] + public void RecordLocalComponent_WithNotNullValue_AddsLocalComponentAnnotation() + { + // Arrange + var testValue = "Some Value"; + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = true; + + var testSpan = new Span(); + + // Act + tracerClient.RecordLocalComponent(testSpan, testValue); + + // Assert + var annotation = testSpan.GetAnnotationsByType().SingleOrDefault(a => a.Key == ZipkinConstants.LocalComponent); + Assert.IsNotNull(annotation, "There is no local trace annotation in the binary annotations."); + Assert.AreEqual(testValue, annotation.Value, "The local component annotation value is not correct."); + } + + [TestMethod] + [TestCategory("TraceRecordTests")] + public void RecordLocalComponent_IsTraceOnIsFalse_DoesNotAddLocalComponentAnnotation() + { + // Arrange + var testValue = "Some Value"; + var tracerClient = SetupZipkinClient(); + spanTracerStub = GetSpanTracerStub(); + var zipkinClient = (ZipkinClient)tracerClient; + zipkinClient.IsTraceOn = false; + + var testSpan = new Span(); + + // Act + tracerClient.RecordBinary(testSpan, ZipkinConstants.LocalComponent, testValue); + + // Assert + Assert.IsFalse(testSpan.GetAnnotationsByType().Any(), "There are annotations but the trace is off."); + } + + private ITracerClient SetupZipkinClient(IZipkinConfig zipkinConfig = null) + { + spanCollectorStub = MockRepository.GenerateStub(new Uri("http://localhost"), (uint)0); traceProvider.Stub(x => x.TraceId).Return(fixture.Create()); traceProvider.Stub(x => x.SpanId).Return(fixture.Create()); @@ -522,28 +522,28 @@ private ITracerClient SetupZipkinClient(IZipkinConfig zipkinConfig = null) context.Stub(x => x.Request).Return(request); context.Stub(x => x.Environment).Return(new Dictionary { { TraceProvider.Key, traceProvider } }); - IZipkinConfig zipkinConfigSetup = zipkinConfig; - if (zipkinConfig == null) - { - zipkinConfigSetup = CreateZipkinConfigWithDefaultValues(); - } - - return new ZipkinClient(zipkinConfigSetup, context, spanCollectorStub); - } - - private IZipkinConfig CreateZipkinConfigWithDefaultValues() - { + IZipkinConfig zipkinConfigSetup = zipkinConfig; + if (zipkinConfig == null) + { + zipkinConfigSetup = CreateZipkinConfigWithDefaultValues(); + } + + return new ZipkinClient(zipkinConfigSetup, context, spanCollectorStub); + } + + private IZipkinConfig CreateZipkinConfigWithDefaultValues() + { return new ZipkinConfig { ZipkinBaseUri = new Uri("http://zipkin.com"), - Domain = new Uri("http://server.com"), + Domain = r => new Uri("http://server.com"), SpanProcessorBatchSize = 123, ExcludedPathList = new List { "/foo", "/bar", "/baz" }, SampleRate = 0.5, NotToBeDisplayedDomainList = new List { ".xyz.net" } - }; - } - + }; + } + private SpanTracer GetSpanTracerStub() { return @@ -553,16 +553,16 @@ private SpanTracer GetSpanTracerStub() new List(), new Uri("http://server.com") ); - } - + } + private void AddTraceId(string traceId) { headers.Add("X-B3-TraceId", new[] { traceId }); - } - + } + private void AddSampled(bool sampled) { headers.Add("X-B3-Sampled", new[] { sampled.ToString() }); - } - } -} + } + } +} diff --git a/tests/Medidata.ZipkinTracer.Core.Test/ZipkinConfigTests.cs b/tests/Medidata.ZipkinTracer.Core.Test/ZipkinConfigTests.cs index 07d2df5..f937a9e 100644 --- a/tests/Medidata.ZipkinTracer.Core.Test/ZipkinConfigTests.cs +++ b/tests/Medidata.ZipkinTracer.Core.Test/ZipkinConfigTests.cs @@ -17,7 +17,7 @@ public void Init() _sut = new ZipkinConfig { ZipkinBaseUri = new Uri("http://zipkin.com"), - Domain = new Uri("http://server.com"), + Domain = r => new Uri("http://server.com"), SpanProcessorBatchSize = fixture.Create(), ExcludedPathList = new List(), SampleRate = 0, @@ -31,14 +31,6 @@ public void Validate() _sut.Validate(); } - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void ValidateWithNullZipkinBaseUri() - { - _sut.Domain = null; - _sut.Validate(); - } - [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidateWithNullDontSampleList() @@ -71,14 +63,6 @@ public void ValidateWithInvalidSampleRate() _sut.Validate(); } - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void ValidateWithNullDomain() - { - _sut.Domain = null; - _sut.Validate(); - } - [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidateWithNullNotToBeDisplayedDomainList() From ca720cfaf3cfc2f6e5123b4e1efe0d40475a8442 Mon Sep 17 00:00:00 2001 From: Peter Mounce Date: Wed, 13 Jul 2016 11:16:01 +0100 Subject: [PATCH 2/3] illustrate domain request delegate use in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8f443f..d4165d6 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ service/environment. var config = new ZipkinConfig { Bypass = request => request.Uri.AbsolutePath.StartsWith("/allowed"), - Domain = new Uri("https://yourservice.com"), + Domain = request => new Uri("https://yourservice.com"), // or, you might like to derive a value from the request, like r => new Uri($"{r.Scheme}://{r.Host}"), ZipkinBaseUri = new Uri("http://zipkin.xyz.net:9411"), SpanProcessorBatchSize = 10, SampleRate = 0.5, From ce3971336c68de7c15a4171a8941fd8dfc0dd8e3 Mon Sep 17 00:00:00 2001 From: Peter Mounce Date: Mon, 18 Jul 2016 17:52:15 +0100 Subject: [PATCH 3/3] code review feedback --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4165d6..164d6ff 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ service/environment. var config = new ZipkinConfig { Bypass = request => request.Uri.AbsolutePath.StartsWith("/allowed"), - Domain = request => new Uri("https://yourservice.com"), // or, you might like to derive a value from the request, like r => new Uri($"{r.Scheme}://{r.Host}"), + Domain = request => new Uri("https://yourservice.com"), // or, you might like to derive a value from the request, like r => new Uri($"{r.Scheme}{Uri.SchemeDelimiter}{r.Host}"), ZipkinBaseUri = new Uri("http://zipkin.xyz.net:9411"), SpanProcessorBatchSize = 10, SampleRate = 0.5,