private WavefrontAspNetCoreReporter(IMetricsRoot metrics, IWavefrontSender wavefrontSender, ApplicationTags applicationTags, string source) { Metrics = metrics; WavefrontSender = wavefrontSender; ApplicationTags = applicationTags; Source = source; }
private WavefrontSpanReporter(IWavefrontSender wavefrontSender, string source, int maxQueueSize, double logPercent, bool reportSpanLogs, ILoggerFactory loggerFactory) { WavefrontSender = wavefrontSender; Source = source; spanBuffer = new BlockingCollection <WavefrontSpan>(maxQueueSize); random = new Random(); this.logPercent = logPercent; logger = loggerFactory.CreateLogger <WavefrontSpanReporter>(); sendTask = Task.Factory.StartNew(SendLoop, TaskCreationOptions.LongRunning); this.reportSpanLogs = reportSpanLogs; }
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); }
private WavefrontAspNetCoreReporter(IMetricsRoot metrics, IWavefrontSender wavefrontSender, ApplicationTags applicationTags, string source) { Metrics = metrics; WavefrontSender = wavefrontSender; ApplicationTags = applicationTags; Source = source; sdkMetricsRegistry = new WavefrontSdkMetricsRegistry .Builder(wavefrontSender) .Prefix(SdkMetricPrefix + ".aspnetcore") .Source(source) .Tags(applicationTags.ToPointTags()) .Build(); double sdkVersion = Utils.GetSemVer(Assembly.GetExecutingAssembly()); sdkMetricsRegistry.Gauge("version", () => sdkVersion); }
/// <summary> /// Add the <see cref="WavefrontReporter" /> allowing metrics to be reported to /// Wavefront. /// </summary> /// <param name="metricReporterProviderBuilder"> /// The <see cref="IMetricsReportingBuilder" /> used to configure metrics reporters. /// </param> /// <param name="wavefrontSender"> /// The <see cref="IWavefrontSender" /> that handles the formatting and flushing of /// metrics to Wavefront, either via direct ingestion or the Wavefront Proxy Agent. /// </param> /// <returns> /// An <see cref="IMetricsBuilder" /> that can be used to further configure App Metrics. /// </returns> public static IMetricsBuilder ToWavefront( this IMetricsReportingBuilder metricReporterProviderBuilder, IWavefrontSender wavefrontSender) { if (metricReporterProviderBuilder == null) { throw new ArgumentNullException(nameof(metricReporterProviderBuilder)); } var options = new MetricsReportingWavefrontOptions { WavefrontSender = wavefrontSender }; var provider = new WavefrontReporter(options); return(metricReporterProviderBuilder.Using(provider)); }
/// <summary> /// Builds a <see cref="WavefrontAspNetCoreReporter"/>. /// </summary> /// <returns>The <see cref="WavefrontAspNetCoreReporter"/> instance.</returns> /// <param name="wavefrontSender"> /// The Wavefront sender instance that handles the sending of data to Wavefront, /// via either Wavefront proxy or direct ingestion. /// </param> public WavefrontAspNetCoreReporter Build(IWavefrontSender wavefrontSender) { source = string.IsNullOrWhiteSpace(source) ? Utils.GetDefaultSource() : source; var globalTags = new Dictionary <string, string> { { ApplicationTagKey, applicationTags.Application } }; if (applicationTags.CustomTags != null) { foreach (var customTag in applicationTags.CustomTags) { if (!globalTags.ContainsKey(customTag.Key)) { globalTags.Add(customTag.Key, customTag.Value); } } } var metrics = new MetricsBuilder() .Configuration.Configure( options => { options.DefaultContextLabel = AspNetCoreContext; options.GlobalTags = new GlobalMetricTags(globalTags); }) .Report.ToWavefront( options => { options.WavefrontSender = wavefrontSender; options.Source = source; options.WavefrontHistogram.ReportMinuteDistribution = true; options.FlushInterval = TimeSpan.FromSeconds(reportingIntervalSeconds); }) .Build(); return(new WavefrontAspNetCoreReporter( metrics, wavefrontSender, applicationTags, source)); }
public MetricSnapshotWavefrontWriter( IWavefrontSender wavefrontSender, string source, IDictionary <string, string> globalTags, ISet <HistogramGranularity> histogramGranularities, WavefrontSdkMetricsRegistry sdkMetricsRegistry, MetricFields fields) { this.wavefrontSender = wavefrontSender; this.source = source; this.globalTags = globalTags; this.histogramGranularities = histogramGranularities; this.fields = fields; gaugesReported = sdkMetricsRegistry.Counter("gauges.reported"); deltaCountersReported = sdkMetricsRegistry.Counter("delta_counters.reported"); countersReported = sdkMetricsRegistry.Counter("counters.reported"); wfHistogramsReported = sdkMetricsRegistry.Counter("wavefront_histograms.reported"); histogramsReported = sdkMetricsRegistry.Counter("histograms.reported"); metersReported = sdkMetricsRegistry.Counter("meters.reported"); timersReported = sdkMetricsRegistry.Counter("timers.reported"); apdexesReported = sdkMetricsRegistry.Counter("apdexes.reported"); writerErrors = sdkMetricsRegistry.Counter("writer.errors"); }
/// <summary> /// Builds and returns a <see cref="WavefrontSpanReporter"/> for sending /// OpenTracing spans to an <see cref="IWavefrontSender"/> that can send to /// Wavefront via either proxy or direct ingestion. /// </summary> /// <returns>A <see cref="WavefrontSpanReporter"/>.</returns> /// <param name="wavefrontSender">The Wavefront sender.</param> public WavefrontSpanReporter Build(IWavefrontSender wavefrontSender) { return(new WavefrontSpanReporter(wavefrontSender, source, maxQueueSize, logPercent, reportSpanLogs, loggerFactory ?? Logging.LoggerFactory)); }
public WavefrontReporter(MetricsReportingWavefrontOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (options.WavefrontSender == null) { throw new ArgumentNullException( nameof(MetricsReportingWavefrontOptions.WavefrontSender)); } wavefrontSender = options.WavefrontSender; source = options.Source; if (options.ApplicationTags != null) { globalTags = new Dictionary <string, string>(options.ApplicationTags.ToPointTags()); } else { globalTags = new Dictionary <string, string>(); } histogramGranularities = new HashSet <HistogramGranularity>(); if (options.WavefrontHistogram.ReportMinuteDistribution) { histogramGranularities.Add(HistogramGranularity.Minute); } if (options.WavefrontHistogram.ReportHourDistribution) { histogramGranularities.Add(HistogramGranularity.Hour); } if (options.WavefrontHistogram.ReportDayDistribution) { histogramGranularities.Add(HistogramGranularity.Day); } if (options.FlushInterval < TimeSpan.Zero) { throw new InvalidOperationException( $"{nameof(MetricsReportingWavefrontOptions.FlushInterval)} " + "must not be less than zero"); } Filter = options.Filter; FlushInterval = options.FlushInterval > TimeSpan.Zero ? options.FlushInterval : AppMetricsConstants.Reporting.DefaultFlushInterval; // Formatting will be handled by the Wavefront sender. Formatter = null; metricFields = options.MetricFields ?? new MetricFields(); var registryBuilder = new WavefrontSdkMetricsRegistry.Builder(wavefrontSender) .Prefix(Constants.SdkMetricPrefix + ".app_metrics") .Source(source) .Tags(globalTags); if (options.LoggerFactory != null) { registryBuilder.LoggerFactory(options.LoggerFactory); } sdkMetricsRegistry = registryBuilder.Build(); reporterErrors = sdkMetricsRegistry.Counter("reporter.errors"); double sdkVersion = Utils.GetSemVer(Assembly.GetExecutingAssembly()); sdkMetricsRegistry.Gauge("version", () => sdkVersion); Logger.Info($"Using Wavefront Reporter {this}. FlushInterval: {FlushInterval}"); }
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 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-appmetrics-sdk-csharp //The URL and token are for direct ingestion of metrics (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"; //Configure a MetricsBuilder object 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 = "TruckWorkflowAnalytics"; }); //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] { "networknerd5", "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 delta counter by 1 MyMetrics.Measure.Counter.Increment(myDeltaCounter); //Force reporting all metrics //end of code instrumentation for metrics await Task.WhenAll(MyMetrics.ReportRunner.RunAllAsync()); //Begin default template code from the HTTP trigger function template as part of the Azure Functions Extension for C#. 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 my own 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."; return(new OkObjectResult(responseMessage)); }
private WavefrontSpanReporter(IWavefrontSender wavefrontSender, string source) { this.wavefrontSender = wavefrontSender; this.source = source; }
/// <summary> /// Builds and returns a <see cref="WavefrontSpanReporter"/> for sending /// OpenTracing spans to an <see cref="IWavefrontSender"/> that can send to /// Wavefront via either proxy or direct ingestion. /// </summary> /// <returns>A <see cref="WavefrontSpanReporter"/>.</returns> /// <param name="wavefrontSender">The Wavefront sender.</param> public WavefrontSpanReporter Build(IWavefrontSender wavefrontSender) { return(new WavefrontSpanReporter(wavefrontSender, source)); }