diff --git a/src/NewRelic.Telemetry.Tests/DataSenderTests.cs b/src/NewRelic.Telemetry.Tests/DataSenderTests.cs index d9b0a40..076ebf6 100644 --- a/src/NewRelic.Telemetry.Tests/DataSenderTests.cs +++ b/src/NewRelic.Telemetry.Tests/DataSenderTests.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Reflection; namespace NewRelic.Telemetry.Tests { @@ -551,5 +552,32 @@ async public Task SendDataAsyncThrowsNonHttpException() Assert.AreEqual(expectedNumSendBatchAsyncCall, actualCountCallsSendData, "Unexpected Number of SendDataAsync calls"); Assert.AreEqual(expectedNumHttpHandlerCall, actualCallsHttpHandler, "Unexpected Number of Http Handler calls"); } + + [TestCase(null, "1.0.0")] + [TestCase("productName", null)] + [TestCase("", "")] + [TestCase(null, null)] + [TestCase("", null)] + [TestCase(null, "")] + [TestCase("productName", "1.0.0")] + public void AddVersionInfo(string productName, string productVersion) + { + var dataSender = new SpanDataSender(new TelemetryConfiguration().WithAPIKey("123456")); + var fieldInfo = dataSender.GetType().GetField("_userAgent", BindingFlags.NonPublic | BindingFlags.Instance); + var userAgentValueBefore = fieldInfo.GetValue(dataSender); + + var expectedUserAgentValue = userAgentValueBefore?.ToString(); + + if(!string.IsNullOrEmpty(productName) && !string.IsNullOrEmpty(productVersion)) + { + expectedUserAgentValue = userAgentValueBefore + " " + $@"{productName}/{productVersion}"; + } + + dataSender.AddVersionInfo(productName, productVersion); + + var userAgentValueAfter = fieldInfo.GetValue(dataSender); + + Assert.AreEqual(expectedUserAgentValue, userAgentValueAfter); + } } } diff --git a/src/NewRelic.Telemetry/PackageVersionAttribute.cs b/src/NewRelic.Telemetry/PackageVersionAttribute.cs index 99b92e5..ec6a997 100644 --- a/src/NewRelic.Telemetry/PackageVersionAttribute.cs +++ b/src/NewRelic.Telemetry/PackageVersionAttribute.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace NewRelic.Telemetry { diff --git a/src/NewRelic.Telemetry/Transport/DataSender.cs b/src/NewRelic.Telemetry/Transport/DataSender.cs index d23ee71..452c758 100644 --- a/src/NewRelic.Telemetry/Transport/DataSender.cs +++ b/src/NewRelic.Telemetry/Transport/DataSender.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; @@ -14,8 +15,8 @@ namespace NewRelic.Telemetry.Transport { public abstract class DataSender where TData : ITelemetryDataType { - private const string _userAgent = "NewRelic-Dotnet-TelemetrySDK"; - private static readonly string _implementationVersion = Assembly.GetExecutingAssembly().GetCustomAttribute().PackageVersion; + protected static readonly string _telemetrySdkVersion = Assembly.GetExecutingAssembly().GetCustomAttribute().PackageVersion; + protected string _userAgent = "NewRelic-Dotnet-TelemetrySDK/" + _telemetrySdkVersion; protected readonly TelemetryConfiguration _config; protected readonly TelemetryLogging _logger; @@ -154,22 +155,6 @@ private async Task RetryWithServerDelay(TData dataToSend, int retryNum return await SendDataAsync(dataToSend, retryNum + 1); } - /// - /// Method used to send a data to New Relic endpoint. Handles the communication with the New Relic endpoints. - /// - /// The data to send to New Relic - /// New Relic response indicating the outcome and additional information about the interaction with the New Relic endpoint. - public async Task SendDataAsync(TData dataToSend) - { - if(string.IsNullOrWhiteSpace(_config.ApiKey)) - { - _logger.Exception(new ArgumentNullException("Configuration requires API key")); - return Response.Failure("API Key was not available"); - } - - return await SendDataAsync(dataToSend, 0); - } - private async Task SendDataAsync(TData dataToSend, int retryNum) { @@ -240,7 +225,9 @@ private async Task SendDataAsync(string serializedPayload) var requestMessage = new HttpRequestMessage(HttpMethod.Post, EndpointUrl); requestMessage.Content = streamContent; - requestMessage.Headers.Add("User-Agent", _userAgent + "/" + _implementationVersion); + + requestMessage.Headers.Add("User-Agent", _userAgent); + requestMessage.Headers.Add("Api-Key", _config.ApiKey); requestMessage.Method = HttpMethod.Post; @@ -254,5 +241,36 @@ private async Task SendDataAsync(string serializedPayload) return response; } } + + /// + /// Method used to send a data to New Relic endpoint. Handles the communication with the New Relic endpoints. + /// + /// The data to send to New Relic + /// New Relic response indicating the outcome and additional information about the interaction with the New Relic endpoint. + public async Task SendDataAsync(TData dataToSend) + { + if (string.IsNullOrWhiteSpace(_config.ApiKey)) + { + _logger.Exception(new ArgumentNullException("Configuration requires API key")); + return Response.Failure("API Key was not available"); + } + + return await SendDataAsync(dataToSend, 0); + } + + /// + /// Method used to add product information including product name and version to the User-Agent HTTP header. + /// + /// Name of the product uses the TelemetrySDK (e.g. "OpenTelemetry.Exporter.NewRelic"). This should not be null or empty. + /// Version of the product uses the TelemetrySDK (e.g. "1.0.0"). This should not be null or empty. + /// + public void AddVersionInfo(string productName, string productVersion) + { + if (!string.IsNullOrEmpty(productName) && !string.IsNullOrEmpty(productVersion)) + { + var productIdentifier = string.Join("/", productName, productVersion); + _userAgent = string.Join(" ", _userAgent, productIdentifier); + } + } } } diff --git a/src/OpenTelemetry.Exporter.NewRelic/NewRelicTraceExporter.cs b/src/OpenTelemetry.Exporter.NewRelic/NewRelicTraceExporter.cs index 43800c2..29f3d7d 100644 --- a/src/OpenTelemetry.Exporter.NewRelic/NewRelicTraceExporter.cs +++ b/src/OpenTelemetry.Exporter.NewRelic/NewRelicTraceExporter.cs @@ -10,6 +10,7 @@ using System.Linq; using OpenTelemetry.Trace.Export; using OpenTelemetry.Trace; +using System.Reflection; namespace OpenTelemetry.Exporter.NewRelic { @@ -19,6 +20,8 @@ namespace OpenTelemetry.Exporter.NewRelic public class NewRelicTraceExporter : SpanExporter { private readonly NRSpans.SpanDataSender _spanDataSender; + private const string _productName = "OpenTelemetry.Exporter.NewRelic"; + private static readonly string _productVersion = Assembly.GetExecutingAssembly().GetCustomAttribute().PackageVersion; private const string _attribName_url = "http.url"; @@ -65,6 +68,7 @@ public NewRelicTraceExporter(TelemetryConfiguration config, ILoggerFactory logge internal NewRelicTraceExporter(NRSpans.SpanDataSender spanDataSender, TelemetryConfiguration config, ILoggerFactory loggerFactory) { _spanDataSender = spanDataSender; + spanDataSender.AddVersionInfo(_productName, _productVersion); _config = config; diff --git a/src/OpenTelemetry.Exporter.NewRelic/OpenTelemetry.Exporter.NewRelic.csproj b/src/OpenTelemetry.Exporter.NewRelic/OpenTelemetry.Exporter.NewRelic.csproj index 996ff07..df5d521 100644 --- a/src/OpenTelemetry.Exporter.NewRelic/OpenTelemetry.Exporter.NewRelic.csproj +++ b/src/OpenTelemetry.Exporter.NewRelic/OpenTelemetry.Exporter.NewRelic.csproj @@ -16,6 +16,20 @@ newrelic New Relic New Relic + + OpenTelemetry.Exporter.NewRelic + newrelic + true + snupkg + + 1 + 0 + 0 + 0 + $(Major).$(Minor).$(Build).$(Revision) + $(Major).$(Minor).$(Build)-beta + $(Major).0.0.0 + $(Major).$(Minor).$(Build).$(Revision) @@ -30,6 +44,10 @@ <_Parameter1>OpenTelemetry.Exporter.NewRelic.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100198f2915b649f8774e7937c4e37e39918db1ad4e83109623c1895e386e964f6aa344aeb61d87ac9bd1f086a7be8a97d90f9ad9994532e5fb4038d9f867eb5ed02066ae24086cf8a82718564ebac61d757c9cbc0cc80f69cc4738f48f7fc2859adfdc15f5dde3e05de785f0ed6b6e020df738242656b02c5c596a11e628752bd0 + + <_Parameter1>$(PackageVersion) + + diff --git a/src/OpenTelemetry.Exporter.NewRelic/PackageVersionAttribute.cs b/src/OpenTelemetry.Exporter.NewRelic/PackageVersionAttribute.cs new file mode 100644 index 0000000..57efd07 --- /dev/null +++ b/src/OpenTelemetry.Exporter.NewRelic/PackageVersionAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace OpenTelemetry.Exporter.NewRelic +{ + [AttributeUsage(AttributeTargets.Assembly)] + public class PackageVersionAttribute : Attribute + { + public string PackageVersion { get; } + public PackageVersionAttribute(string version) + { + PackageVersion = version; + } + } +}