/// <inheritdoc />
        public IEnumerable <string> ExportToFiles(Summary summary, ILogger consoleLogger)
        {
            DateTimeOffset startTime = DateTimeOffset.UtcNow;
            Exception      exception = null;

            try
            {
                Tracer tracer = new Tracer();

                foreach (var report in summary.Reports)
                {
                    Span   span = tracer.StartSpan("benchmarkdotnet.test", startTime: startTime);
                    double durationNanoseconds = 0;

                    span.SetMetric(Tags.Analytics, 1.0d);
                    span.SetTraceSamplingPriority(SamplingPriority.UserKeep);
                    span.Type         = "test";
                    span.ResourceName = $"{report.BenchmarkCase.Descriptor.Type.FullName}.{report.BenchmarkCase.Descriptor.WorkloadMethod.Name}";
                    CIEnvironmentValues.DecorateSpan(span);

                    span.SetTag(TestTags.Name, report.BenchmarkCase.Descriptor.WorkloadMethodDisplayInfo);
                    span.SetTag(TestTags.Type, TestTags.TypeBenchmark);
                    span.SetTag(TestTags.Suite, report.BenchmarkCase.Descriptor.Type.FullName);
                    span.SetTag(TestTags.Framework, $"BenchmarkDotNet {summary.HostEnvironmentInfo.BenchmarkDotNetVersion}");
                    span.SetTag(TestTags.Status, report.Success ? TestTags.StatusPass : TestTags.StatusFail);

                    if (summary.HostEnvironmentInfo != null)
                    {
                        span.SetTag("benchmark.host.processor.name", ProcessorBrandStringHelper.Prettify(summary.HostEnvironmentInfo.CpuInfo.Value));
                        span.SetMetric("benchmark.host.processor.physical_processor_count", summary.HostEnvironmentInfo.CpuInfo.Value.PhysicalProcessorCount);
                        span.SetMetric("benchmark.host.processor.physical_core_count", summary.HostEnvironmentInfo.CpuInfo.Value.PhysicalCoreCount);
                        span.SetMetric("benchmark.host.processor.logical_core_count", summary.HostEnvironmentInfo.CpuInfo.Value.LogicalCoreCount);
                        span.SetMetric("benchmark.host.processor.max_frequency_hertz", summary.HostEnvironmentInfo.CpuInfo.Value.MaxFrequency?.Hertz);
                        span.SetTag("benchmark.host.os_version", summary.HostEnvironmentInfo.OsVersion.Value);
                        span.SetTag("benchmark.host.runtime_version", summary.HostEnvironmentInfo.RuntimeVersion);
                        span.SetMetric("benchmark.host.chronometer.frequency_hertz", summary.HostEnvironmentInfo.ChronometerFrequency.Hertz);
                        span.SetMetric("benchmark.host.chronometer.resolution", summary.HostEnvironmentInfo.ChronometerResolution.Nanoseconds);
                    }

                    if (report.BenchmarkCase.Job != null)
                    {
                        var job = report.BenchmarkCase.Job;
                        span.SetTag("benchmark.job.description", job.DisplayInfo);

                        if (job.Environment != null)
                        {
                            var jobEnv = job.Environment;
                            span.SetTag("benchmark.job.environment.platform", jobEnv.Platform.ToString());

                            if (jobEnv.Runtime != null)
                            {
                                span.SetTag("benchmark.job.runtime.name", jobEnv.Runtime.Name);
                                span.SetTag("benchmark.job.runtime.moniker", jobEnv.Runtime.MsBuildMoniker);
                            }
                        }
                    }

                    if (report.ResultStatistics != null)
                    {
                        var stats = report.ResultStatistics;
                        span.SetMetric("benchmark.runs", stats.N);
                        span.SetMetric("benchmark.duration.mean", stats.Mean);

                        span.SetMetric("benchmark.statistics.n", stats.N);
                        span.SetMetric("benchmark.statistics.max", stats.Max);
                        span.SetMetric("benchmark.statistics.min", stats.Min);
                        span.SetMetric("benchmark.statistics.mean", stats.Mean);
                        span.SetMetric("benchmark.statistics.median", stats.Median);
                        span.SetMetric("benchmark.statistics.std_dev", stats.StandardDeviation);
                        span.SetMetric("benchmark.statistics.std_err", stats.StandardError);
                        span.SetMetric("benchmark.statistics.kurtosis", stats.Kurtosis);
                        span.SetMetric("benchmark.statistics.skewness", stats.Skewness);

                        if (stats.Percentiles != null)
                        {
                            span.SetMetric("benchmark.statistics.p90", stats.Percentiles.P90);
                            span.SetMetric("benchmark.statistics.p95", stats.Percentiles.P95);
                            span.SetMetric("benchmark.statistics.p99", stats.Percentiles.Percentile(99));
                        }

                        durationNanoseconds = stats.N * stats.Mean;
                    }

                    if (report.Metrics != null)
                    {
                        foreach (var keyValue in report.Metrics)
                        {
                            if (keyValue.Value is null || keyValue.Value.Descriptor is null)
                            {
                                continue;
                            }

                            span.SetTag($"benchmark.metrics.{keyValue.Key}.displayName", keyValue.Value.Descriptor.DisplayName);
                            span.SetTag($"benchmark.metrics.{keyValue.Key}.legend", keyValue.Value.Descriptor.Legend);
                            span.SetTag($"benchmark.metrics.{keyValue.Key}.unit", keyValue.Value.Descriptor.Unit);
                            span.SetMetric($"benchmark.metrics.{keyValue.Key}.value", keyValue.Value.Value);
                        }
                    }

                    if (report.BenchmarkCase.Config?.HasMemoryDiagnoser() == true)
                    {
                        span.SetMetric("benchmark.memory.gen0Collections", report.GcStats.Gen0Collections);
                        span.SetMetric("benchmark.memory.gen1Collections", report.GcStats.Gen1Collections);
                        span.SetMetric("benchmark.memory.gen2Collections", report.GcStats.Gen2Collections);
                        span.SetMetric("benchmark.memory.total_operations", report.GcStats.TotalOperations);
                        span.SetMetric("benchmark.memory.mean_bytes_allocations", report.GcStats.BytesAllocatedPerOperation);
                        span.SetMetric("benchmark.memory.total_bytes_allocations", report.GcStats.GetTotalAllocatedBytes(false));
                    }

                    var duration = TimeSpan.FromTicks((long)(durationNanoseconds / TimeConstants.NanoSecondsPerTick));
                    span.Finish(startTime.Add(duration));
                }
            }
            catch (Exception ex)
            {
                exception = ex;
                consoleLogger.WriteLine(LogKind.Error, ex.ToString());
            }

            if (exception is null)
            {
                return(new string[] { "Datadog Exporter ran successfully." });
            }
            else
            {
                return(new string[] { "Datadog Exporter error: " + exception.ToString() });
            }
        }
Example #2
0
 public void IntroCoreIsPrettified(string originalName, string prettifiedName) =>
 Assert.Equal(prettifiedName, ProcessorBrandStringHelper.Prettify(originalName));
        public override void ExportToLog(Summary summary, ILogger logger)
        {
            // We construct HostEnvironmentInfo manually, so that we can have the HardwareTimerKind enum as text, rather than an integer
            // SimpleJson serialiser doesn't seem to have an enum String/Value option (to-be-fair, it is meant to be "Simple")
            var environmentInfo = new
            {
                HostEnvironmentInfo.BenchmarkDotNetCaption,
                summary.HostEnvironmentInfo.BenchmarkDotNetVersion,
                OsVersion     = summary.HostEnvironmentInfo.OsVersion.Value,
                ProcessorName = ProcessorBrandStringHelper.Prettify(summary.HostEnvironmentInfo.CpuInfo.Value?.ProcessorName ?? ""),
                summary.HostEnvironmentInfo.CpuInfo.Value?.PhysicalProcessorCount,
                summary.HostEnvironmentInfo.CpuInfo.Value?.PhysicalCoreCount,
                summary.HostEnvironmentInfo.CpuInfo.Value?.LogicalCoreCount,
                summary.HostEnvironmentInfo.RuntimeVersion,
                summary.HostEnvironmentInfo.Architecture,
                summary.HostEnvironmentInfo.HasAttachedDebugger,
                summary.HostEnvironmentInfo.HasRyuJit,
                summary.HostEnvironmentInfo.Configuration,
                summary.HostEnvironmentInfo.JitModules,
                DotNetCliVersion = summary.HostEnvironmentInfo.DotNetSdkVersion.Value,
                summary.HostEnvironmentInfo.ChronometerFrequency,
                HardwareTimerKind = summary.HostEnvironmentInfo.HardwareTimerKind.ToString()
            };

            // If we just ask SimpleJson to serialise the entire "summary" object it throws several errors.
            // So we are more specific in what we serialise (plus some fields/properties aren't relevant)

            var benchmarks = summary.Reports.Select(r =>
            {
                var data = new Dictionary <string, object>
                {
                    // We don't need Benchmark.ShortInfo, that info is available via Benchmark.Parameters below
                    { "DisplayInfo", r.Benchmark.DisplayInfo },
                    { "Namespace", r.Benchmark.Target.Type.Namespace },
                    { "Type", r.Benchmark.Target.Type.Name },
                    { "Method", r.Benchmark.Target.Method.Name },
                    { "MethodTitle", r.Benchmark.Target.MethodDisplayInfo },
                    { "Parameters", r.Benchmark.Parameters.PrintInfo },
                    { "FullName", XUnitNameProvider.GetBenchmarkName(r.Benchmark) }, // do NOT remove this property, it is used for xunit-performance migration
                    // { "Properties", r.Benchmark.Job.ToSet().ToDictionary(p => p.Name, p => p.Value) }, // TODO
                    { "Statistics", r.ResultStatistics },
                };

                // We show MemoryDiagnoser's results only if it is being used
                if (summary.Config.HasMemoryDiagnoser())
                {
                    data.Add("Memory", r.GcStats);
                }

                if (ExcludeMeasurements == false)
                {
                    // We construct Measurements manually, so that we can have the IterationMode enum as text, rather than an integer
                    data.Add("Measurements",
                             r.AllMeasurements.Select(m => new
                    {
                        IterationMode = m.IterationMode.ToString(),
                        m.LaunchIndex,
                        m.IterationIndex,
                        m.Operations,
                        m.Nanoseconds
                    }));
                }

                return(data);
            });

            JsonSerialiser.CurrentJsonSerializerStrategy.Indent = IndentJson;
            logger.WriteLine(JsonSerialiser.SerializeObject(new Dictionary <string, object>
            {
                { "Title", summary.Title },
                { "HostEnvironmentInfo", environmentInfo },
                { "Benchmarks", benchmarks }
            }));
        }