/// <summary> /// Processes an incoming telemetry batch for OpenCensus channel. /// </summary> /// <remarks>This method may be called from multiple threads concurrently.</remarks> private void OnOcBatchReceived(ExportSpanRequest batch) { try { // send incoming telemetry items to the telemetryClient foreach (Span span in batch.Spans) { try { //!!! Diagnostics.LogTrace($"OpenCensus message received: {batch.Spans.Count} spans, first span: {batch.Spans.First().Name}"); this.telemetryClient.TrackSpan(span, this.ocToAiInstrumentationKey); } catch (Exception e) { // an unexpected issue while tracking an item // log and carry on Diagnostics.LogError( FormattableString.Invariant( $"Could not track an incoming OpenCensus telemetry item. {e.ToString()}")); } } } catch (Exception e) { // an unexpected issue while processing the batch // log and carry on Diagnostics.LogError( FormattableString.Invariant( $"Could not process an incoming OpenCensus telemetry batch. {e.ToString()}")); } }
public async Task GrpcOpenCensusInputTests_StopsAndRestarts() { // ARRANGE int batchesReceived = 0; ExportSpanRequest receivedBatch = null; int port = GetPort(); var input = new GrpcOpenCensusInput("localhost", port); input.Start(exportSpanRequest => { batchesReceived++; receivedBatch = exportSpanRequest; }); Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout)); var grpcWriter = new GrpcWriter(false, port); ExportSpanRequest batch = new ExportSpanRequest(); batch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Event1" } }); await grpcWriter.Write(batch).ConfigureAwait(false); Common.AssertIsTrueEventually( () => input.GetStats().BatchesReceived == 1 && batchesReceived == 1 && receivedBatch.Spans.Single().Name.Value == "Event1", GrpcOpenCensusInputTests.DefaultTimeout); // ACT input.Stop(); Common.AssertIsTrueEventually( () => !input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 1 && receivedBatch.Spans.Single().Name.Value == "Event1", GrpcOpenCensusInputTests.DefaultTimeout); input.Start(exportSpanRequest => { batchesReceived++; receivedBatch = exportSpanRequest; }); Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout)); grpcWriter = new GrpcWriter(false, port); batch.Spans.Single().Name.Value = "Event2"; await grpcWriter.Write(batch).ConfigureAwait(false); // ASSERT Common.AssertIsTrueEventually( () => input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 2 && receivedBatch.Spans.Single().Name.Value == "Event2", GrpcOpenCensusInputTests.DefaultTimeout); }
public async Task HostTests_StopsLibrary() { // ARRANGE var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems); int portAI = Common.GetPort(); int portOC = Common.GetPort(); var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?> <LocalForwarderConfiguration> <Inputs> <ApplicationInsightsInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portAI}</Port> </ApplicationInsightsInput> <OpenCensusInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portOC}</Port> </OpenCensusInput> </Inputs> <OpenCensusToApplicationInsights> <InstrumentationKey>ikey1</InstrumentationKey> </OpenCensusToApplicationInsights> </LocalForwarderConfiguration> "; Host host = new Host(telemetryClient); host.Run(config, TimeSpan.FromSeconds(5)); Thread.Sleep(TimeSpan.FromMilliseconds(250)); // ACT host.Stop(); Thread.Sleep(TimeSpan.FromMilliseconds(250)); var telemetryBatch = new ExportSpanRequest(); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span1" }, Kind = Span.Types.SpanKind.Server }); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span2" }, Kind = Span.Types.SpanKind.Client }); // ASSERT var writer = new GrpcWriter(false, portOC); await writer.Write(telemetryBatch).ConfigureAwait(false); Assert.Fail(); }
public async Task Write(ExportSpanRequest batch) { if (this.aiMode) { throw new InvalidOperationException("Incorrect mode"); } try { await this.openCensusStreamingCall.RequestStream.WriteAsync(batch).ConfigureAwait(false); } catch (System.Exception e) { throw new InvalidOperationException( FormattableString.Invariant($"Error sending a message via gRpc. {e.ToString()}")); } }
public async Task GrpcOpenCensusInputTests_ReceivesDataFromMultipleClients() { // ARRANGE int batchesReceived = 0; ExportSpanRequest receivedBatch = null; int port = GetPort(); var input = new GrpcOpenCensusInput("localhost", port); input.Start(exportSpanRequest => { Interlocked.Increment(ref batchesReceived); receivedBatch = exportSpanRequest; }); Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout)); // ACT ExportSpanRequest batch = new ExportSpanRequest(); batch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Event1" } }); Parallel.For(0, 1000, new ParallelOptions() { MaxDegreeOfParallelism = 1000 }, async i => { var grpcWriter = new GrpcWriter(false, port); await grpcWriter.Write(batch).ConfigureAwait(false); }); // ASSERT Common.AssertIsTrueEventually( () => input.GetStats().BatchesReceived == 1000 && batchesReceived == 1000, GrpcOpenCensusInputTests.DefaultTimeout); input.Stop(); Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout)); }
public async Task GrpcOpenCensusInputTests_HandlesExceptionsInProcessingHandler() { // ARRANGE int port = GetPort(); var input = new GrpcOpenCensusInput("localhost", port); input.Start(exportSpanRequest => throw new InvalidOperationException()); Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout)); var grpcWriter = new GrpcWriter(false, port); ExportSpanRequest batch = new ExportSpanRequest(); batch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Event1" } }); // ACT await grpcWriter.Write(batch).ConfigureAwait(false); // ASSERT // must have handled the exception by logging it // should still be able to process items Common.AssertIsTrueEventually( () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 1, GrpcOpenCensusInputTests.DefaultTimeout); await grpcWriter.Write(batch).ConfigureAwait(false); Common.AssertIsTrueEventually( () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 2, GrpcOpenCensusInputTests.DefaultTimeout); }
public async Task LibraryTests_LibraryProcessesOcBatchesCorrectly() { // ARRANGE var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems); int portAI = Common.GetPort(); int portOC = Common.GetPort(); var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?> <LocalForwarderConfiguration> <Inputs> <ApplicationInsightsInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portAI}</Port> </ApplicationInsightsInput> <OpenCensusInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portOC}</Port> </OpenCensusInput> </Inputs> <OpenCensusToApplicationInsights> <InstrumentationKey>ikey1</InstrumentationKey> </OpenCensusToApplicationInsights> <ApplicationInsights> <LiveMetricsStreamInstrumentationKey>[SPECIFY LIVE METRICS STREAM INSTRUMENTATION KEY HERE]</LiveMetricsStreamInstrumentationKey> </ApplicationInsights> </LocalForwarderConfiguration> "; var telemetryBatch = new ExportSpanRequest(); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span1" }, Kind = Span.Types.SpanKind.Server }); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span2" }, Kind = Span.Types.SpanKind.Client }); var lib = new Library(config, telemetryClient); lib.Run(); // ACT var writer = new GrpcWriter(false, portOC); await writer.Write(telemetryBatch).ConfigureAwait(false); // ASSERT Common.AssertIsTrueEventually(() => sentItems.Count == 2); lib.Stop(); Assert.AreEqual("Span1", (sentItems.Skip(0).First() as RequestTelemetry).Name); Assert.AreEqual("Span2", (sentItems.Skip(1).First() as DependencyTelemetry).Name); }
public async Task HostTests_RestartsLibraryIfStoppedUnexpectedly() { // ARRANGE var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems); int portAI = Common.GetPort(); int portOC = Common.GetPort(); var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?> <LocalForwarderConfiguration> <Inputs> <ApplicationInsightsInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portAI}</Port> </ApplicationInsightsInput> <OpenCensusInput Enabled=""true""> <Host>0.0.0.0</Host> <Port>{portOC}</Port> </OpenCensusInput> </Inputs> <OpenCensusToApplicationInsights> <InstrumentationKey>ikey1</InstrumentationKey> </OpenCensusToApplicationInsights> <ApplicationInsights> <LiveMetricsStreamInstrumentationKey>ikey1</LiveMetricsStreamInstrumentationKey> </ApplicationInsights> </LocalForwarderConfiguration> "; Host host = new Host(telemetryClient); host.Run(config, TimeSpan.FromSeconds(1)); FieldInfo libraryFieldInfo = host.GetType().GetField("library", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null); // ACT // stop the existing library (as if something went wrong) var library = libraryFieldInfo.GetValue(host) as Library; library.Stop(); Common.AssertIsTrueEventually(() => !library.IsRunning); // ASSERT // wait for a new library Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null); // verify the new library works var telemetryBatch = new ExportSpanRequest(); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span1" }, Kind = Span.Types.SpanKind.Server }); telemetryBatch.Spans.Add(new Span() { Name = new TruncatableString() { Value = "Span2" }, Kind = Span.Types.SpanKind.Client }); var writer = new GrpcWriter(false, portOC); await writer.Write(telemetryBatch).ConfigureAwait(false); Common.AssertIsTrueEventually(() => sentItems.Count == 2); Assert.AreEqual("Span1", (sentItems.Skip(0).First() as RequestTelemetry).Name); Assert.AreEqual("Span2", (sentItems.Skip(1).First() as DependencyTelemetry).Name); }