-
Notifications
You must be signed in to change notification settings - Fork 157
Expand file tree
/
Copy pathJsonTelemetryTransport.cs
More file actions
117 lines (98 loc) · 5.88 KB
/
JsonTelemetryTransport.cs
File metadata and controls
117 lines (98 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// <copyright file="JsonTelemetryTransport.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>
#nullable enable
using System;
using System.Net;
using System.Threading.Tasks;
using Datadog.Trace.Agent;
using Datadog.Trace.Agent.Transports;
using Datadog.Trace.Logging;
using Datadog.Trace.PlatformHelpers;
using Datadog.Trace.Telemetry.Metrics;
using Datadog.Trace.Util;
using Datadog.Trace.Util.Http;
using Datadog.Trace.Vendors.Newtonsoft.Json;
using Datadog.Trace.Vendors.Newtonsoft.Json.Serialization;
namespace Datadog.Trace.Telemetry.Transports
{
internal abstract class JsonTelemetryTransport : ITelemetryTransport
{
protected static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor<JsonTelemetryTransport>();
internal static readonly JsonSerializerSettings SerializerSettings = new() { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy(), } };
private readonly IApiRequestFactory _requestFactory;
private readonly Uri _endpoint;
private readonly ContainerMetadata _containerMetadata;
private readonly bool _enableDebug;
private readonly bool _telemetryGzipCompressionEnabled;
protected JsonTelemetryTransport(IApiRequestFactory requestFactory, bool enableDebug, string telemetryCompressionMethod, ContainerMetadata containerMetadata)
{
_requestFactory = requestFactory;
_enableDebug = enableDebug;
_endpoint = _requestFactory.GetEndpoint(TelemetryConstants.TelemetryPath);
_containerMetadata = containerMetadata;
_telemetryGzipCompressionEnabled = telemetryCompressionMethod.Equals("gzip", StringComparison.OrdinalIgnoreCase);
}
protected string GetEndpointInfo() => _requestFactory.Info(_endpoint);
public async Task<TelemetryPushResult> PushTelemetry(TelemetryData data)
{
var endpointMetricTag = GetEndpointMetricTag();
try
{
var request = _requestFactory.Create(_endpoint);
request.AddHeader(TelemetryConstants.ApiVersionHeader, data.ApiVersion);
request.AddHeader(TelemetryConstants.RequestTypeHeader, data.RequestType);
if (_enableDebug)
{
request.AddHeader(TelemetryConstants.DebugHeader, "true");
}
var sessionId = RuntimeId.Get();
request.AddHeader(TelemetryConstants.SessionIdHeader, sessionId);
var rootSessionId = RuntimeId.GetRootSessionId();
if (rootSessionId != sessionId)
{
request.AddHeader(TelemetryConstants.RootSessionIdHeader, rootSessionId);
}
request.AddContainerMetadataHeaders(_containerMetadata);
TelemetryFactory.Metrics.RecordCountTelemetryApiRequests(endpointMetricTag);
using var response = await request.PostAsJsonAsync(data, _telemetryGzipCompressionEnabled ? MultipartCompression.GZip : MultipartCompression.None, SerializerSettings).ConfigureAwait(false);
TelemetryFactory.Metrics.RecordCountTelemetryApiResponses(endpointMetricTag, response.GetTelemetryStatusCodeMetricTag());
if (response.StatusCode is >= 200 and < 300)
{
Log.Debug("Telemetry sent successfully. CompressionEnabled {Compression}", _telemetryGzipCompressionEnabled);
return TelemetryPushResult.Success;
}
TelemetryFactory.Metrics.RecordCountTelemetryApiErrors(endpointMetricTag, MetricTags.ApiError.StatusCode);
if (response.StatusCode == 404)
{
Log.Debug("Error sending telemetry: 404. Disabling further telemetry, as endpoint '{Endpoint}' not found. CompressionEnabled {Compression}", GetEndpointInfo(), _telemetryGzipCompressionEnabled);
return TelemetryPushResult.FatalError;
}
Log.Debug("Error sending telemetry to '{Endpoint}' {StatusCode} . CompressionEnabled {Compression}", GetEndpointInfo(), response.StatusCode, _telemetryGzipCompressionEnabled);
return TelemetryPushResult.TransientFailure;
}
catch (Exception ex) when (IsFatalException(ex))
{
Log.Information(ex, "Error sending telemetry data, unable to communicate with '{Endpoint}'. CompressionEnabled {Compression}", GetEndpointInfo(), _telemetryGzipCompressionEnabled);
var tag = ex is TimeoutException ? MetricTags.ApiError.Timeout : MetricTags.ApiError.NetworkError;
TelemetryFactory.Metrics.RecordCountTelemetryApiErrors(endpointMetricTag, tag);
return TelemetryPushResult.FatalError;
}
catch (Exception ex)
{
Log.Information(ex, "Error sending telemetry data to '{Endpoint}'. CompressionEnabled {Compression}", GetEndpointInfo(), _telemetryGzipCompressionEnabled);
var tag = ex is TimeoutException ? MetricTags.ApiError.Timeout : MetricTags.ApiError.NetworkError;
TelemetryFactory.Metrics.RecordCountTelemetryApiErrors(endpointMetricTag, tag);
return TelemetryPushResult.TransientFailure;
}
}
public abstract string GetTransportInfo();
protected abstract MetricTags.TelemetryEndpoint GetEndpointMetricTag();
private static bool IsFatalException(Exception ex)
{
return ex.IsSocketException()
|| ex is WebException { Response: HttpWebResponse { StatusCode: HttpStatusCode.NotFound } };
}
}
}