public static IServiceCollection AddWavefrontProxy(this IServiceCollection services, IConfiguration configuration) { var waveFrontProxyConfiguration = configuration.GetSection(WavefrontProxyOptions.WavefrontProxy).Get <WavefrontProxyOptions>(); var wfProxyClientBuilder = new WavefrontProxyClient.Builder(waveFrontProxyConfiguration.Hostname); wfProxyClientBuilder.MetricsPort(waveFrontProxyConfiguration.Port); wfProxyClientBuilder.DistributionPort(waveFrontProxyConfiguration.DistributionPort); wfProxyClientBuilder.TracingPort(waveFrontProxyConfiguration.TracingPort); wfProxyClientBuilder.FlushIntervalSeconds(waveFrontProxyConfiguration.TracingPort); var wavefrontSender = wfProxyClientBuilder.Build(); var applicationTags = new ApplicationTags.Builder(waveFrontProxyConfiguration.Application, waveFrontProxyConfiguration.Service) .Cluster(waveFrontProxyConfiguration.Cluster) .Shard(waveFrontProxyConfiguration.Shard) .Build(); var wfAspNetCoreReporter = new WavefrontAspNetCoreReporter.Builder(applicationTags) .WithSource(waveFrontProxyConfiguration.Source) .ReportingIntervalSeconds(waveFrontProxyConfiguration.ReportingIntervalSeconds) .Build(wavefrontSender); System.Console.WriteLine(wfAspNetCoreReporter); var wavefrontSpanReporter = new WavefrontSpanReporter.Builder() .Build(wavefrontSender); ITracer tracer = new WavefrontTracer.Builder(wavefrontSpanReporter, applicationTags).Build(); services.AddWavefrontForMvc(wfAspNetCoreReporter, tracer); return(services); }
public static IServiceCollection AddWavefrontDirectIngestion(this IServiceCollection services, IConfiguration configuration) { var waveFrontDirectIngestionConfiguration = configuration.GetSection(WavefrontDirectIngestionOptions.WavefrontDirectIngestion) .Get <WavefrontDirectIngestionOptions>(); var applicationTags = new ApplicationTags.Builder(waveFrontDirectIngestionConfiguration.Application, waveFrontDirectIngestionConfiguration.Service) .Cluster(waveFrontDirectIngestionConfiguration.Cluster) .Shard(waveFrontDirectIngestionConfiguration.Shard) .Build(); var wfDirectIngestionClientBuilder = new WavefrontDirectIngestionClient.Builder(waveFrontDirectIngestionConfiguration.Hostname, waveFrontDirectIngestionConfiguration.Token); wfDirectIngestionClientBuilder.MaxQueueSize(waveFrontDirectIngestionConfiguration.MaxQueueSize); wfDirectIngestionClientBuilder.BatchSize(waveFrontDirectIngestionConfiguration.BatchSize); wfDirectIngestionClientBuilder.FlushIntervalSeconds(waveFrontDirectIngestionConfiguration.FlushIntervalSeconds); var wavefrontSender = wfDirectIngestionClientBuilder.Build(); var wfAspNetCoreReporter = new WavefrontAspNetCoreReporter.Builder(applicationTags) .WithSource(waveFrontDirectIngestionConfiguration.Source) .ReportingIntervalSeconds(waveFrontDirectIngestionConfiguration.ReportingIntervalSeconds) .Build(wavefrontSender); var wavefrontSpanReporter = new WavefrontSpanReporter.Builder() .Build(wavefrontSender); ITracer tracer = new WavefrontTracer.Builder(wavefrontSpanReporter, applicationTags).Build(); services.AddWavefrontForMvc(wfAspNetCoreReporter, tracer); return(services); }
private void ConfigureWavefront(IServiceCollection services) { var appTagsConfig = new ConfigurationBuilder() .AddYamlFile(Path.Combine(env.ContentRootPath, Configuration["applicationTagsYamlFile"])) .Build(); ApplicationTags applicationTags = ConstructApplicationTags(appTagsConfig); var wfReportingConfig = new ConfigurationBuilder() .AddYamlFile(Path.Combine(env.ContentRootPath, Configuration["wfReportingConfigYamlFile"])) .Build(); string source = wfReportingConfig["source"]; if (string.IsNullOrWhiteSpace(source)) { source = Dns.GetHostName(); } IWavefrontSender wavefrontSender = ConstructWavefrontSender(wfReportingConfig); WavefrontAspNetCoreReporter wfAspNetCoreReporter = new WavefrontAspNetCoreReporter .Builder(applicationTags) .WithSource(source) .Build(wavefrontSender); ITracer tracer; if (wfReportingConfig.GetValue <bool>("reportTraces")) { WavefrontSpanReporter wavefrontSpanReporter = new WavefrontSpanReporter .Builder() .WithSource(source) .Build(wavefrontSender); var consoleReporter = new ConsoleReporter(source); var compositeReporter = new CompositeReporter(wavefrontSpanReporter, consoleReporter); tracer = new WavefrontTracer .Builder(compositeReporter, applicationTags) .Build(); } else { tracer = null; } services.AddWavefrontForMvc(wfAspNetCoreReporter, tracer); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { //Begin code instrumentation - reference https://github.com/wavefrontHQ/wavefront-opentracing-sdk-csharp //The application, service, cluster, and shard variables are all metadata to be added to each span created. string application = "VMworld2020Demo"; string service = "GlobalDataAggregator"; string cluster = "Azure"; string shard = "networknerd4"; //The URL and token are for direct ingestion of metrics, traces, and spans (no proxy in use here). //The API token can be found inside the Tanzu Observability (Wavefront) web UI and is unique to your environment. Click the gear icon in the upper right, click your e-mail address, and then select API Access. string wfURL = "https://vmware.wavefront.com"; string token = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Create ApplicationTags - for tracing purposes ApplicationTags applicationTags = new ApplicationTags.Builder(application, service).Cluster(cluster).Shard(shard).Build(); //Configure a MetricsBuilder object - for custom metrics sent via the Metrics SDK var MyMetricsBuilder = new MetricsBuilder(); //Initialize WavefrontDirectIngestionClient WavefrontDirectIngestionClient.Builder wfDirectIngestionClientBuilder = new WavefrontDirectIngestionClient.Builder(wfURL, token); // Create an IWavefrontSender instance for sending data via direct ingestion. IWavefrontSender wavefrontSender = wfDirectIngestionClientBuilder.Build(); //Configure MeetricsBuilder to Report to Wavefront with proper sender object and source tag specified. In this case my source is the function name. MyMetricsBuilder.Report.ToWavefront( options => { options.WavefrontSender = wavefrontSender; options.Source = "TruckGlobalDataAggregator"; }); //Build IMetrics instance var MyMetrics = MyMetricsBuilder.Build(); //These are arrays for key value pairs to add as metric tags. You can add some or many here as you instrument your code. string[] keys = new string[3] { "FunctionApp", "Cloud", "Region" }; string[] values = new string[3] { "networknerd4", "Azure", "Central-US" }; // Configure and instantiate a DeltaCounter using DeltaCounterOptions.Builder. The metric name is azure.function.execution.deltacounter. var myDeltaCounter = new DeltaCounterOptions.Builder("azure.function.execution.deltacounter").MeasurementUnit(Unit.Calls).Tags(new MetricTags(keys, values)).Build(); // Increment the counter by 1 MyMetrics.Measure.Counter.Increment(myDeltaCounter); //Force reporting all custom metrics await Task.WhenAll(MyMetrics.ReportRunner.RunAllAsync()); //Create a WavefrontSpanReporter for reporting trace data that originates on <sourceName>. The source is the function name in this case. IReporter wfSpanReporter = new WavefrontSpanReporter.Builder() .WithSource("TruckGlobalDataAggregator").Build(wavefrontSender); //Create CompositeReporter and ConsoleReporter objects for more OpenTracing metrics IReporter consoleReporter = new ConsoleReporter("TruckGlobalDataAggregator"); IReporter compositeReporter = new CompositeReporter(wfSpanReporter, consoleReporter); //Create the WavefrontTracer. WavefrontTracer MyTracer = new WavefrontTracer.Builder(wfSpanReporter, applicationTags).Build(); //The variable MyDictionary is needed to extract span context in case a call is made from another function / outside this function. IDictionary <string, string> MyDictionary = new Dictionary <string, string>(); foreach (var entry in req.Headers) { MyDictionary.TryAdd(entry.Key, entry.Value); } //Attempt to pull span fontext from HTTP headers passed into this function to continue a span across environments. The proper context will be loaded into the variable //ctx if so. The second line of code loads all metadata from the span context. ITextMap carrier = new TextMapExtractAdapter(MyDictionary); OpenTracing.ISpanContext ctx = MyTracer.Extract(BuiltinFormats.HttpHeaders, carrier); OpenTracing.IScope receivingScope = MyTracer.BuildSpan("TruckGlobalDataAggregator.Execute").AsChildOf(ctx).StartActive(true); //Start building a new span called TruckGlobalDataAggregator.Execute if there was no context passed into headers. if (MyTracer.ActiveSpan != null) { MyTracer.BuildSpan("TruckGlobalDataAggregator.Execute").StartActive(); } log.LogInformation("C# HTTP trigger function processed a request."); string name = req.Query["name"]; string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody); name = name ?? data?.name; //Add function execution delays based on input - for personal testing only. if (string.Equals(name, "0.5")) { await Task.Delay(500); } if (string.Equals(name, "1")) { await Task.Delay(1000); } if (string.Equals(name, "1.5")) { await Task.Delay(1500); } if (string.Equals(name, "2")) { await Task.Delay(2000); } string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $"Hello, {name}. This HTTP triggered function executed successfully."; //Finish the span MyTracer.ActiveSpan.Finish(); //Close the tracer before application exit MyTracer.Close(); return(new OkObjectResult(responseMessage)); }
public void TestDebugWavefrontSpan() { string operationName = "dummyOp"; var wfSenderMock = new Mock <IWavefrontSender>(MockBehavior.Strict); wfSenderMock.Reset(); Expression <Action <IWavefrontSender> > sendSpan = sender => sender.SendSpan(operationName, IsAny <long>(), IsAny <long>(), "source", IsAny <Guid>(), IsAny <Guid>(), new List <Guid>(), new List <Guid>(), IsAny <IList <KeyValuePair <string, string> > >(), new List <SpanLog>()); Expression <Action <IWavefrontSender> > sendInvocationCount = sender => sender.SendMetric( "∆tracing.derived.myApplication.myService.dummyOp.invocation.count", 1.0, null, "source", IsAny <IDictionary <string, string> >()); Expression <Action <IWavefrontSender> > sendTotalMillis = sender => sender.SendMetric( "∆tracing.derived.myApplication.myService.dummyOp.total_time.millis.count", IsAny <double>(), null, "source", IsAny <IDictionary <string, string> >()); Expression <Action <IWavefrontSender> > sendDurationMicros = sender => sender.SendDistribution( "tracing.derived.myApplication.myService.dummyOp.duration.micros", IsAny <IList <KeyValuePair <double, int> > >(), new HashSet <HistogramGranularity> { HistogramGranularity.Minute }, IsAny <long>(), "source", IsAny <IDictionary <string, string> >()); Expression <Action <IWavefrontSender> > sendHeartbeat = sender => sender.SendMetric( "~component.heartbeat", 1.0, IsAny <long>(), "source", IsAny <IDictionary <string, string> >()); wfSenderMock.Setup(sendSpan); wfSenderMock.Setup(sendInvocationCount); wfSenderMock.Setup(sendTotalMillis); wfSenderMock.Setup(sendDurationMicros); wfSenderMock.Setup(sendHeartbeat); WavefrontSpanReporter spanReporter = new WavefrontSpanReporter.Builder() .WithSource("source").Build(wfSenderMock.Object); WavefrontTracer tracer = new WavefrontTracer.Builder(spanReporter, BuildApplicationTags()).SetReportFrequency(TimeSpan.FromMilliseconds(50)) .WithSampler(new RateSampler(0.0)).Build(); tracer.BuildSpan(operationName).WithTag("debug", true) .StartActive(true).Span.Finish(DateTimeOffset.Now.AddMilliseconds(10)); Console.WriteLine("Sleeping for 1 second zzzzz ....."); Thread.Sleep(1000); Console.WriteLine("Resuming execution ....."); wfSenderMock.Verify(sendSpan, Times.Once()); wfSenderMock.Verify(sendInvocationCount, Times.AtLeastOnce()); wfSenderMock.Verify(sendTotalMillis, Times.AtLeastOnce()); /* * TODO: update WavefrontHistogramOptions.Builder to allow a clock to be passed in * so that we can advance minute bin and update the below call to Times.AtLeastOnce() */ wfSenderMock.Verify(sendDurationMicros, Times.AtMost(int.MaxValue)); wfSenderMock.Verify(sendHeartbeat, Times.AtMost(int.MaxValue)); }
public void TestErrorWavefrontSpan() { string operationName = "dummyOp"; var pointTags = PointTags(operationName, new Dictionary <string, string> { { Tags.SpanKind.Key, Constants.NullTagValue } }); var errorTags = PointTags(operationName, new Dictionary <string, string> { { Tags.SpanKind.Key, Constants.NullTagValue }, { Tags.HttpStatus.Key, "404" } }); var histogramTags = PointTags(operationName, new Dictionary <string, string> { { Tags.SpanKind.Key, Constants.NullTagValue }, { "error", "true" } }); var wfSenderMock = new Mock <IWavefrontSender>(MockBehavior.Strict); Expression <Action <IWavefrontSender> > sendSpan = sender => sender.SendSpan(operationName, IsAny <long>(), IsAny <long>(), "source", IsAny <Guid>(), IsAny <Guid>(), new List <Guid>(), new List <Guid>(), IsAny <IList <KeyValuePair <string, string> > >(), new List <SpanLog>()); Expression <Action <IWavefrontSender> > sendInvocationCount = sender => sender.SendMetric( "tracing.derived.myApplication.myService.dummyOp.invocation.count", 1.0, IsAny <long>(), "source", Is <IDictionary <string, string> >(dict => ContainsPointTags(dict, pointTags))); Expression <Action <IWavefrontSender> > sendErrorCount = sender => sender.SendMetric( "tracing.derived.myApplication.myService.dummyOp.error.count", 1.0, IsAny <long>(), "source", Is <IDictionary <string, string> >(dict => ContainsPointTags(dict, errorTags))); Expression <Action <IWavefrontSender> > sendTotalMillis = sender => sender.SendMetric( "tracing.derived.myApplication.myService.dummyOp.total_time.millis.count", IsAny <double>(), IsAny <long>(), "source", Is <IDictionary <string, string> >(dict => ContainsPointTags(dict, pointTags))); Expression <Action <IWavefrontSender> > sendDurationMicros = sender => sender.SendDistribution( "tracing.derived.myApplication.myService.dummyOp.duration.micros", IsAny <IList <KeyValuePair <double, int> > >(), new HashSet <HistogramGranularity> { HistogramGranularity.Minute }, IsAny <long>(), "source", Is <IDictionary <string, string> >(dict => ContainsPointTags(dict, histogramTags))); Expression <Action <IWavefrontSender> > sendHeartbeat = sender => sender.SendMetric( "~component.heartbeat", 1.0, IsAny <long>(), "source", IsAny <IDictionary <string, string> >()); wfSenderMock.Setup(sendSpan); wfSenderMock.Setup(sendInvocationCount); wfSenderMock.Setup(sendErrorCount); wfSenderMock.Setup(sendTotalMillis); wfSenderMock.Setup(sendDurationMicros); wfSenderMock.Setup(sendHeartbeat); WavefrontSpanReporter spanReporter = new WavefrontSpanReporter.Builder() .WithSource("source").Build(wfSenderMock.Object); WavefrontTracer tracer = new WavefrontTracer.Builder(spanReporter, BuildApplicationTags()).SetReportFrequency(TimeSpan.FromMilliseconds(50)).Build(); tracer.BuildSpan(operationName).WithTag(Tags.Error, true).WithTag(Tags.HttpStatus, 404) .StartActive(true).Dispose(); Console.WriteLine("Sleeping for 1 second zzzzz ....."); Thread.Sleep(1000); Console.WriteLine("Resuming execution ....."); wfSenderMock.Verify(sendSpan, Times.Once()); wfSenderMock.Verify(sendInvocationCount, Times.AtLeastOnce()); wfSenderMock.Verify(sendErrorCount, Times.AtLeastOnce()); wfSenderMock.Verify(sendTotalMillis, Times.AtLeastOnce()); /* * TODO: update WavefrontHistogramOptions.Builder to allow a clock to be passed in * so that we can advance minute bin and update the below call to Times.AtLeastOnce() */ wfSenderMock.Verify(sendDurationMicros, Times.AtMost(int.MaxValue)); wfSenderMock.Verify(sendHeartbeat, Times.AtMost(int.MaxValue)); }