public void TestFixedTargetAndRateBehaveCorrectly() { var strategy = new LocalizedSamplingStrategy(); strategy.Rules.Add(new Core.Sampling.Local.SamplingRule("name", "test", "get", 10, 0.05)); int count = 0; // fill the fixed target rate Action action = () => { var input = new SamplingInput("name", "test", "get", "", ""); if (strategy.ShouldTrace(input).SampleDecision == SampleDecision.Sampled) { Interlocked.Increment(ref count); } }; var actions = Enumerable.Repeat(action, 10).ToArray(); Parallel.Invoke(actions); Assert.AreEqual(10, count); count = 0; var samplingInput = new SamplingInput("name", "test", "get", "", ""); for (int i = 0; i < 200; i++) { count += strategy.ShouldTrace(samplingInput).SampleDecision == SampleDecision.Sampled ? 1 : 0; } // Default sample rate is 5%. The chance that count == 0 after 200 tries is 0.003%. Assert.IsTrue(count > 0); Assert.IsTrue(count < 50); }
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 ); }
public void TestLocalFallbackRules() // If rules are not loaded by default sampler, use local rules { var strategy = new DefaultSamplingStrategy($"JSONs{Path.DirectorySeparatorChar}SamplingRules1.json"); var input = new SamplingInput("name", "test", "get", "", ""); var samplingResponse = strategy.ShouldTrace(input); Assert.AreEqual(SampleDecision.Sampled, samplingResponse.SampleDecision); Assert.IsTrue(string.IsNullOrEmpty(samplingResponse.RuleName)); }
public void TestGetMatchedRuleForExpiredCache1() // Cache not loaded, hould return null { RuleCache ruleCache = new RuleCache(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "dynamo", "*"); TimeStamp current = TimeStamp.CurrentTime(); var actualRule = ruleCache.GetMatchedRule(samplingInput, current); // cache is expired since never loaded Assert.IsNull(actualRule); }
private static SamplingResponse MakeSamplingDecision(HttpRequest request, TraceHeader traceHeader, string name) { string host = request.Headers.Get("Host"); string url = request.Url.AbsolutePath; string method = request.HttpMethod; SamplingInput samplingInput = new SamplingInput(host, url, method, name, _recorder.Origin); SamplingResponse sampleResponse = _recorder.SamplingStrategy.ShouldTrace(samplingInput); traceHeader.Sampled = sampleResponse.SampleDecision; return(sampleResponse); }
public void TestGetMatchedRule3() // sampling input ServiceName and ServiceType is null - it should be ignored for rule matching { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "", ""); SamplingRule expectedRule = GetSamplingRule("a", 1, 0.5, 10, samplingInput.Host, "test", samplingInput.Method, samplingInput.Url, serviceType: "XYZ"); newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsTrue(actualRule.Equals(expectedRule)); }
public void TestGetMatchedRule4() // sampling input has only ServiceName - the rule should be matched { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk"); SamplingRule expectedRule = GetSamplingRule("a", 1, 0.5, 10, serviceName: samplingInput.ServiceName); newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsTrue(actualRule.Equals(expectedRule)); }
public void TestGetMatchedRuleNotMatching() // Rule not matched { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "dynamo", "*"); SamplingRule rule = GetSamplingRule("a", 1, 0.5, 10, "j", samplingInput.ServiceName, samplingInput.Method, samplingInput.Url); newRules.Add(rule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsNull(actualRule); }
public void TestGetMatchedRuleNotMatching2() // SamplingInput with only ServiceName - Rule not matched { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk"); SamplingRule rule = GetSamplingRule("a", 1, 0.5, 10, serviceName: "XYZ"); newRules.Add(rule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsNull(actualRule); }
public void TestGetMatchedRule2() // ServiceType is different { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "dynamo", "AWS::ECS::Container"); SamplingRule expectedRule = GetSamplingRule("a", 1, 0.5, 10, samplingInput.Host, samplingInput.ServiceName, samplingInput.Method, samplingInput.Url, serviceType: "XYZ"); newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsNull(actualRule); }
public void TestGetMatchedRuleForExpiredCache2() // Expired cache should not match rule. { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "dynamo", "*"); SamplingRule expectedRule = GetSamplingRule("a", 1, 0.5, 10, samplingInput.Host, samplingInput.ServiceName, samplingInput.Method, samplingInput.Url); newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated.Time = current.Time; current.Time += RuleCache.TTL + 1; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); // cache is expired, though matching rule is present Assert.IsNull(actualRule); }
public void TestDefaultRuleWithRequest() { var request = new HttpRequestMessage { RequestUri = new Uri(@"http://www.amazon.com/api/product"), Method = HttpMethod.Post }; request.Headers.Add("Host", "www.amazon.com"); var strategy = new LocalizedSamplingStrategy(); string host = request.Headers.Host; string url = request.RequestUri.AbsolutePath; string method = request.Method.Method; SamplingInput samplingInput = new SamplingInput(host, url, method, "", ""); SamplingResponse samplingResponse = strategy.ShouldTrace(samplingInput); Assert.AreEqual(SampleDecision.Sampled, samplingResponse.SampleDecision); Assert.IsTrue(string.IsNullOrEmpty(samplingResponse.RuleName)); }
public void TestGetMatchedRuleWithDefaultRule2() // SamplingInput with only ServiceName - Matching with default Rule; { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk"); SamplingRule rule = GetSamplingRule("a", 1, 0.5, 10, serviceName: "XYZ"); newRules.Add(rule); SamplingRule expectedRule = GetSamplingRule(SamplingRule.Default, 10000, 0.5, 1, "j", "*", "*", "*"); // should match to default rule newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsTrue(actualRule.Equals(expectedRule)); }
public void TestGetMatchedRuleWithDefaultRule() // Matching with default Rule; { RuleCache ruleCache = new RuleCache(); List <SamplingRule> newRules = new List <SamplingRule>(); SamplingInput samplingInput = new SamplingInput("elasticbeanstalk", "/api/1", "GET", "dynamo", "*"); SamplingRule rule = GetSamplingRule("a", 1, 0.5, 10, "j", "test", samplingInput.Method, samplingInput.Url); newRules.Add(rule); SamplingRule expectedRule = GetSamplingRule(SamplingRule.Default, 10000, 0.5, 1, "j", "*", "*", "*"); // should match to default rule newRules.Add(expectedRule); ruleCache.LoadRules(newRules); TimeStamp current = TimeStamp.CurrentTime(); ruleCache.LastUpdated = current; var actualRule = ruleCache.GetMatchedRule(samplingInput, current); Assert.IsTrue(actualRule.Equals(expectedRule)); }
public void TestNotInitializeSamplingStrategy() { SamplingInput input = new SamplingInput("randomName", "testPath", "get", "test", "*"); _recorder.SamplingStrategy.ShouldTrace(input); }
public SamplingResponse ShouldTrace(SamplingInput input) { throw new NotImplementedException(); }
/// <summary> /// Perform sampling decison based on <see cref="SamplingInput"/>. /// </summary> /// <param name="input"> Instance of <see cref="SamplingInput"/>.</param> /// <returns>Instance of <see cref="SamplingResponse"/>.</returns> public SamplingResponse ShouldTrace(SamplingInput input) { SampleDecision sampleDecision = Sample(input.Host, input.Url, input.Method); return(new SamplingResponse(sampleDecision)); }
/// <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 }; } 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 = 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> /// 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; string ruleName = 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; string segmentName = SegmentNamingStrategy.GetSegmentName(request); // Make sample decision if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) { string host = request.Headers.Host; string url = request.RequestUri.AbsolutePath; string method = request.Method.Method; SamplingInput samplingInput = new SamplingInput(host, url, method, segmentName, _recorder.Origin); SamplingResponse s = _recorder.SamplingStrategy.ShouldTrace(samplingInput); traceHeader.Sampled = s.SampleDecision; ruleName = s.RuleName; } SamplingResponse samplingResponse = new SamplingResponse(ruleName, traceHeader.Sampled); // get final ruleName and SampleDecision _recorder.BeginSegment(segmentName, traceHeader.RootTraceId, traceHeader.ParentId, samplingResponse); 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); }