public void TestElasticBeanstalkPlugin() { var mockEBPlugin = new Mock <IPlugin>(); IDictionary <string, object> fakeEBContext = new Dictionary <string, object>(); fakeEBContext.Add("deployment_id", "1"); fakeEBContext.Add("environment_id", "1"); fakeEBContext.Add("environment_name", "test"); fakeEBContext.Add("version_label", "v0"); mockEBPlugin.Setup(x => x.Origin).Returns("AWS::ElasticBeanstalk::Environment"); mockEBPlugin.Setup(x => x.ServiceName).Returns("elastic_beanstalk"); mockEBPlugin.Setup(x => x.TryGetRuntimeContext(out fakeEBContext)).Returns(true); var recorder = new AWSXRayRecorderBuilder().WithPlugin(mockEBPlugin.Object).Build(); var traceId = TraceId.NewId(); recorder.BeginSegment(GetType().Name, traceId); Thread.Sleep(100); recorder.EndSegment(); #if NET45 var response = BatchGetTraces(traceId); #else var response = BatchGetTracesAsync(traceId).Result; #endif Assert.IsTrue(response.Traces.Count > 0); var segmentJsonData = JsonMapper.ToObject(response.Traces[0].Segments[0].Document); Assert.AreEqual("AWS::ElasticBeanstalk::Environment", (string)segmentJsonData["origin"]); var ebJsonData = segmentJsonData["aws"]["elastic_beanstalk"]; Assert.AreEqual("1", (string)ebJsonData["deployment_id"]); Assert.AreEqual("1", (string)ebJsonData["environment_id"]); Assert.AreEqual("test", (string)ebJsonData["environment_name"]); Assert.AreEqual("v0", (string)ebJsonData["version_label"]); }
public void TestEC2Plugin() { var mockEC2Plugin = new Mock <IPlugin>(); IDictionary <string, object> fakeEC2Context = new Dictionary <string, object>(); fakeEC2Context.Add("instance_id", "i-0ae00afcb550c1164"); fakeEC2Context.Add("availability_zone", "us-east-1d"); fakeEC2Context.Add("instance_size", "c4.large"); fakeEC2Context.Add("ami_id", "ami-a32a7eb4"); mockEC2Plugin.Setup(x => x.Origin).Returns("AWS::EC2::Instance"); mockEC2Plugin.Setup(x => x.ServiceName).Returns("ec2"); mockEC2Plugin.Setup(x => x.TryGetRuntimeContext(out fakeEC2Context)).Returns(true); var recorder = new AWSXRayRecorderBuilder().WithPlugin(mockEC2Plugin.Object).Build(); var traceId = TraceId.NewId(); recorder.BeginSegment(GetType().Name, traceId); Thread.Sleep(100); recorder.EndSegment(); #if NET45 var response = BatchGetTraces(traceId); #else var response = BatchGetTracesAsync(traceId).Result; #endif Assert.IsTrue(response.Traces.Count > 0); var segmentJsonData = JsonMapper.ToObject(response.Traces[0].Segments[0].Document); Assert.AreEqual("AWS::EC2::Instance", (string)segmentJsonData["origin"]); var ec2JsonData = segmentJsonData["aws"]["ec2"]; Assert.AreEqual("i-0ae00afcb550c1164", (string)ec2JsonData["instance_id"]); Assert.AreEqual("us-east-1d", (string)ec2JsonData["availability_zone"]); Assert.AreEqual("c4.large", (string)ec2JsonData["instance_size"]); Assert.AreEqual("ami-a32a7eb4", (string)ec2JsonData["ami_id"]); }
public void TestECSPlugin() { var mockECSPlugin = new Mock <IPlugin>(); IDictionary <string, object> fakeECSContext = new Dictionary <string, object>(); fakeECSContext.Add("container", "localhost"); mockECSPlugin.Setup(x => x.Origin).Returns("AWS::ECS::Container"); mockECSPlugin.Setup(x => x.ServiceName).Returns("ecs"); mockECSPlugin.Setup(x => x.TryGetRuntimeContext(out fakeECSContext)).Returns(true); var recorder = new AWSXRayRecorderBuilder().WithPlugin(mockECSPlugin.Object).Build(); var traceId = TraceId.NewId(); recorder.BeginSegment(GetType().Name, traceId); Thread.Sleep(100); recorder.EndSegment(); #if NET45 var response = BatchGetTraces(traceId); #else var response = BatchGetTracesAsync(traceId).Result; #endif Assert.IsTrue(response.Traces.Count > 0); var segmentJsonData = JsonMapper.ToObject(response.Traces[0].Segments[0].Document); Assert.AreEqual("AWS::ECS::Container", (string)segmentJsonData["origin"]); var ecsJsonData = segmentJsonData["aws"]["ecs"]; Assert.AreEqual("localhost", (string)ecsJsonData["container"]); }
public static void ContinueFrom(this AWSXRayRecorder recorder, string serviceName, Message message) { var traceHeader = message?.GetTraceHeader() ?? new TraceHeader { RootTraceId = TraceId.NewId(), ParentId = null, Sampled = SampleDecision.Unknown }; string ruleName = null; if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) { var samplingInput = new SamplingInput(serviceName); var sampleResponse = recorder.SamplingStrategy.ShouldTrace(samplingInput); traceHeader.Sampled = sampleResponse.SampleDecision; ruleName = sampleResponse.RuleName; } var samplingResponse = new SamplingResponse(ruleName, traceHeader.Sampled); recorder .BeginSegment ( serviceName, traceHeader.RootTraceId, traceHeader.ParentId, samplingResponse ); }
/// <summary> /// Processes HTTP request. /// </summary> private void ProcessHTTPRequest(HttpContext context) { HttpRequest request = context.Request; string headerString = null; if (request.Headers.TryGetValue(TraceHeader.HeaderKey, out StringValues headerValue)) { if (headerValue.ToArray().Length >= 1) { headerString = headerValue.ToArray()[0]; } } // Trace header doesn't exist, which means this is the root node. Create a new traceId and inject the trace header. if (!TraceHeader.TryParse(headerString, out TraceHeader traceHeader)) { _logger.DebugFormat("Trace header doesn't exist or not valid : ({0}). Injecting a new one.", headerString); traceHeader = new TraceHeader { RootTraceId = TraceId.NewId(), ParentId = null, Sampled = SampleDecision.Unknown }; } bool isSampleDecisionRequested = traceHeader.Sampled == SampleDecision.Requested; // Make sample decision if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) { string serviceName = request.Host.Host; string url = request.Path; string method = request.Method; traceHeader.Sampled = _recorder.SamplingStrategy.Sample(serviceName, url, method); } if (AWSXRayRecorder.Instance.IsLambda()) { _recorder.BeginSubsegment(SegmentNamingStrategy.GetSegmentName(request)); } else { _recorder.BeginSegment(SegmentNamingStrategy.GetSegmentName(request), traceHeader.RootTraceId, traceHeader.ParentId, traceHeader.Sampled); } if (!AWSXRayRecorder.Instance.IsTracingDisabled()) { var requestAttributes = new Dictionary <string, object>(); PopulateRequestAttributes(request, requestAttributes); _recorder.AddHttpInformation("request", requestAttributes); } if (isSampleDecisionRequested) { context.Response.Headers.Add(TraceHeader.HeaderKey, traceHeader.ToString()); // Its recommended not to modify response header after _next.Invoke() call } }
/// <summary> /// Returns instance of <see cref="TraceHeader"/> class from given <see cref="HttpContext"/> object. /// </summary> private static TraceHeader GetTraceHeader(HttpContext context) { var request = context.Request; string headerString = request.Headers.Get(TraceHeader.HeaderKey); // Trace header doesn't exist, which means this is the root node. Create a new traceId and inject the trace header. if (!TraceHeader.TryParse(headerString, out TraceHeader traceHeader)) { _logger.DebugFormat("Trace header doesn't exist or not valid : ({0}). Injecting a new one.", headerString); traceHeader = new TraceHeader { RootTraceId = TraceId.NewId(), ParentId = null, Sampled = SampleDecision.Unknown }; } return(traceHeader); }
private static void GetSamplingDetails( IAWSXRayRecorder xRayRecorder, string serviceName, string traceHeader, out string traceId, out SamplingResponse samplingResponse, out string parentId) { if (TraceHeader.TryParse(traceHeader, out TraceHeader header)) { traceId = header.RootTraceId; samplingResponse = new SamplingResponse { SampleDecision = header.Sampled }; parentId = header.ParentId; } else { traceId = TraceId.NewId(); samplingResponse = xRayRecorder.SamplingStrategy.ShouldTrace(new SamplingInput { ServiceName = serviceName }); parentId = null; } }
public void TestMultipleSubsegments() { var traceId = TraceId.NewId(); Recorder.BeginSegment(GetType().Name, traceId); for (int i = 0; i < 3; i++) { Recorder.BeginSubsegment("downstream" + i); Recorder.EndSubsegment(); } Dictionary <string, string> subsegmentNames = new Dictionary <string, string>(); TraceContext.GetEntity().Subsegments.ForEach(x => subsegmentNames[x.Id] = x.Name); Recorder.EndSegment(); #if NET45 var response = BatchGetTraces(traceId); #else var response = BatchGetTracesAsync(traceId).Result; #endif Assert.IsTrue(response.Traces.Count > 0); var segmentJsonData = JsonMapper.ToObject(response.Traces[0].Segments[0].Document); var subsegments = segmentJsonData["subsegments"]; Assert.IsNotNull(subsegments); Assert.AreEqual(3, subsegments.Count); for (int i = 0; i < 3; i++) { Assert.AreEqual((string)subsegments[i]["name"], (string)subsegmentNames[(string)subsegments[i]["id"]]); subsegmentNames.Remove((string)subsegments[i]["id"]); } Assert.AreEqual(0, subsegmentNames.Count); }
public void TestMinimalSegment() { var traceId = TraceId.NewId(); Recorder.BeginSegment(GetType().Name, traceId); var segment = TraceContext.GetEntity(); Thread.Sleep(100); Recorder.EndSegment(); #if NET45 var response = BatchGetTraces(traceId); #else var response = BatchGetTracesAsync(traceId).Result; #endif Assert.IsTrue(response.Traces.Count > 0); var segmentJsonData = JsonMapper.ToObject(response.Traces[0].Segments[0].Document); Assert.AreEqual(traceId, (string)segmentJsonData["trace_id"]); Assert.AreEqual(segment.Id, (string)segmentJsonData["id"]); Assert.AreEqual(segment.Name, (string)segmentJsonData["name"]); Assert.AreEqual(segment.StartTime.ToString("F5"), ((double)segmentJsonData["start_time"]).ToString("F5")); Assert.AreEqual(segment.EndTime.ToString("F5"), ((double)segmentJsonData["end_time"]).ToString("F5")); }
private void Seed(AppUserContext appUserContext, OutboxContext outboxContext, ILogger <Startup> logger) { // XRAY - EFCore - AsyncLocal Problems string traceId = TraceId.NewId(); AWSXRayRecorder.Instance.BeginSegment("DB Migration", traceId); try { logger.LogInformation("Initializing AppUserContext Database Migration."); appUserContext.Database.Migrate(); logger.LogInformation("Finishing AppUserContext Database Migration..."); logger.LogInformation("Initializing OutboxContext Database Migration."); outboxContext.Database.Migrate(); logger.LogInformation("Finishing OutboxContext Database Migration..."); } catch (Exception) { AWSXRayRecorder.Instance.AddException(e); } finally { AWSXRayRecorder.Instance.EndSegment(); } }
/// <summary> /// Sends an HTTP request to the inner handler to send to the server as an asynchronous /// operation. /// </summary> /// <param name="request">The HTTP request message to send to the server.</param> /// <param name="cancellationToken">A cancellation token to cancel operation.</param> /// <returns>Returns System.Threading.Tasks.Task. The task object representing the asynchronous operation.</returns> protected async override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { string headerSring = null; if (request.Headers.TryGetValues(TraceHeader.HeaderKey, out IEnumerable <string> headerValue)) { headerSring = headerValue.First(); } // If Trace header doesn't exist, which means this is the root node. Create a new traceId and inject the trace header. if (!TraceHeader.TryParse(headerSring, out TraceHeader traceHeader)) { _logger.DebugFormat("Trace header doesn't exist or not valid. Injecting a new one. existing header = {0}", headerSring); traceHeader = new TraceHeader { RootTraceId = TraceId.NewId(), ParentId = null, Sampled = SampleDecision.Unknown }; } bool isSampleDecisionRequested = traceHeader.Sampled == SampleDecision.Requested; // Make sample decision if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) { traceHeader.Sampled = _recorder.SamplingStrategy.Sample(request); } _recorder.BeginSegment(SegmentNamingStrategy.GetSegmentName(request), traceHeader.RootTraceId, traceHeader.ParentId, traceHeader.Sampled); if (!AppSettings.IsXRayTracingDisabled) { var requestAttributes = new Dictionary <string, object>(); requestAttributes["url"] = request.RequestUri.AbsoluteUri; requestAttributes["method"] = request.Method.Method; string xForwardedFor = GetXForwardedFor(request); if (xForwardedFor == null) { requestAttributes["client_ip"] = GetClientIpAddress(request); } else { requestAttributes["client_ip"] = xForwardedFor; requestAttributes["x_forwarded_for"] = true; } requestAttributes["user_agent"] = request.Headers.UserAgent.ToString(); _recorder.AddHttpInformation("request", requestAttributes); } var response = await base.SendAsync(request, cancellationToken); if (!AppSettings.IsXRayTracingDisabled) { var responseAttributes = new Dictionary <string, object>(); int statusCode = (int)response.StatusCode; if (statusCode >= 400 && statusCode <= 499) { _recorder.MarkError(); if (statusCode == 429) { _recorder.MarkThrottle(); } } else if (statusCode >= 500 && statusCode <= 599) { _recorder.MarkFault(); } responseAttributes["status"] = statusCode; if (response.Content != null && response.Content.Headers.ContentLength != null) { responseAttributes["content_length"] = response.Content.Headers.ContentLength; } _recorder.AddHttpInformation("response", responseAttributes); } _recorder.EndSegment(); // If the sample decision is requested, added the trace header to response if (isSampleDecisionRequested) { response.Headers.Add(TraceHeader.HeaderKey, traceHeader.ToString()); } return(response); }
/// <summary> /// Process http request. /// </summary> internal static void ProcessRequest(HttpContext httpContext) { HttpRequest request = httpContext.Request; string headerString = null; if (request.Headers.TryGetValue(TraceHeader.HeaderKey, out StringValues headerValue)) { if (headerValue.Count >= 1) { headerString = headerValue[0]; } } if (!TraceHeader.TryParse(headerString, out TraceHeader traceHeader)) { _logger.DebugFormat("Trace header doesn't exist or not valid : ({0}). Injecting a new one.", headerString); traceHeader = new TraceHeader { RootTraceId = TraceId.NewId(), ParentId = null, Sampled = SampleDecision.Unknown }; } var segmentName = SegmentNamingStrategy.GetSegmentName(request); bool isSampleDecisionRequested = traceHeader.Sampled == SampleDecision.Requested; string ruleName = null; // Make sample decision if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) { string host = request.Host.Host; string url = request.Path; string method = request.Method; SamplingInput samplingInput = new SamplingInput(host, url, method, segmentName, _recorder.Origin); SamplingResponse sampleResponse = _recorder.SamplingStrategy.ShouldTrace(samplingInput); traceHeader.Sampled = sampleResponse.SampleDecision; ruleName = sampleResponse.RuleName; } if (AWSXRayRecorder.IsLambda()) { _recorder.BeginSubsegment(segmentName); } else { SamplingResponse samplingResponse = new SamplingResponse(ruleName, traceHeader.Sampled); // get final ruleName and SampleDecision _recorder.BeginSegment(SegmentNamingStrategy.GetSegmentName(request), traceHeader.RootTraceId, traceHeader.ParentId, samplingResponse); } if (!AWSXRayRecorder.Instance.IsTracingDisabled()) { var requestAttributes = PopulateRequestAttributes(request); _recorder.AddHttpInformation("request", requestAttributes); } // Mark the segment as auto-instrumented AgentUtil.AddAutoInstrumentationMark(); if (isSampleDecisionRequested) { httpContext.Response.Headers.Add(TraceHeader.HeaderKey, traceHeader.ToString()); // Its recommended not to modify response header after _next.Invoke() call } }
/// <inheritdoc/> public string CreateId() { return(TraceId.NewId()); }