-
Notifications
You must be signed in to change notification settings - Fork 147
/
Copy pathLambdaCommon.cs
140 lines (121 loc) · 4.83 KB
/
LambdaCommon.cs
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// <copyright file="LambdaCommon.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>
#if NET6_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Datadog.Trace.Headers;
using Datadog.Trace.Propagators;
using Datadog.Trace.Telemetry;
using Datadog.Trace.Telemetry.Metrics;
using Datadog.Trace.Util;
namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Lambda;
internal abstract class LambdaCommon
{
private const string PlaceholderServiceName = "placeholder-service";
private const string PlaceholderOperationName = "placeholder-operation";
private const double ServerlessMaxWaitingFlushTime = 3;
private const string LogLevelEnvName = "DD_LOG_LEVEL";
internal static Scope CreatePlaceholderScope(Tracer tracer, NameValueHeadersCollection headers)
{
var context = tracer.TracerManager.SpanContextPropagator.Extract(headers).MergeBaggageInto(Baggage.Current);
var span = tracer.StartSpan(
PlaceholderOperationName,
tags: null,
parent: context.SpanContext,
serviceName: PlaceholderServiceName,
addToTraceContext: false);
TelemetryFactory.Metrics.RecordCountSpanCreated(MetricTags.IntegrationName.AwsLambda);
return tracer.TracerManager.ScopeManager.Activate(span, false);
}
internal static Scope SendStartInvocation(ILambdaExtensionRequest requestBuilder, string data, IDictionary<string, string> context)
{
var request = requestBuilder.GetStartInvocationRequest();
WriteRequestPayload(request, data);
WriteRequestHeaders(request, context);
using var response = (HttpWebResponse)request.GetResponse();
var headers = response.Headers.Wrap();
if (!ValidateOkStatus(response))
{
return null;
}
var tracer = Tracer.Instance;
return CreatePlaceholderScope(tracer, headers);
}
internal static void SendEndInvocation(ILambdaExtensionRequest requestBuilder, Scope scope, bool isError, string data)
{
var request = requestBuilder.GetEndInvocationRequest(scope, isError);
WriteRequestPayload(request, data);
using var response = (HttpWebResponse)request.GetResponse();
if (!ValidateOkStatus(response))
{
Log("Extension does not send a status 200 OK", debug: false);
}
}
internal static async Task FlushTracesAsync()
{
try
{
await Tracer.Instance.TracerManager.AgentWriter.FlushTracesAsync()
.WaitAsync(TimeSpan.FromSeconds(ServerlessMaxWaitingFlushTime))
.ConfigureAwait(false);
}
catch (Exception ex)
{
Log("Could not flush to the extension", ex, false);
}
}
internal static async Task EndInvocationAsync(string returnValue, Exception exception, Scope scope, ILambdaExtensionRequest requestBuilder)
{
await FlushTracesAsync().ConfigureAwait(false);
try
{
if (exception != null && scope is { Span: var span })
{
span.SetException(exception);
}
SendEndInvocation(requestBuilder, scope, exception != null, returnValue);
}
catch (Exception ex)
{
Log("Could not send payload to the extension", ex, false);
}
scope?.Dispose();
}
private static bool ValidateOkStatus(HttpWebResponse response)
{
var statusCode = response.StatusCode;
Log("The extension responds with statusCode = " + statusCode);
return statusCode == HttpStatusCode.OK;
}
private static void WriteRequestPayload(WebRequest request, string data)
{
var byteArray = Encoding.UTF8.GetBytes(data);
request.ContentLength = byteArray.Length;
var dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
private static void WriteRequestHeaders(WebRequest request, IDictionary<string, string> context)
{
if (context != null)
{
foreach (var kv in context)
{
request.Headers.Add(kv.Key, kv.Value);
}
}
}
internal static void Log(string message, Exception ex = null, bool debug = true)
{
if (!debug || EnvironmentHelpers.GetEnvironmentVariable(LogLevelEnvName)?.ToLower() == "debug")
{
Console.WriteLine($"{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss:fff} [DD_TRACE_DOTNET] {message} {ex?.ToString().Replace("\n", "\\n")}");
}
}
}
#endif