//-----------------------------------------------------------------------------
//
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//-----------------------------------------------------------------------------
using Amazon.Runtime.Internal.Util;
using Amazon.XRay.Recorder.Core;
using Amazon.XRay.Recorder.Core.Internal.Utils;
using Amazon.XRay.Recorder.Core.Sampling.Local;
using System;
namespace Amazon.XRay.Recorder.Core.Sampling
{
///
/// Making sampling decisions based on sampling rules defined
/// by X-Ray control plane APIs.It will fall back to if
/// sampling rules are not available.
///
public class DefaultSamplingStrategy : ISamplingStrategy
{
private static readonly Logger _logger = Logger.GetLogger(typeof(DefaultSamplingStrategy));
private ISamplingStrategy _localFallbackRules;
private RuleCache _ruleCache;
private RulePoller _rulePoller;
private TargetPoller _targetPoller;
private IConnector _connector;
private bool _isPollerStarted = false;
private readonly Object _lock = new Object();
///
/// Instance of .
///
public DaemonConfig DaemonCfg { get; private set; }
///
/// Instance of .
///
public XRayConfig XRayConfig = null;
///
/// Instance of .
///
public DefaultSamplingStrategy()
{
_localFallbackRules = new LocalizedSamplingStrategy();
InititalizeStrategy();
}
///
/// Instance of .
///
/// Path to local sampling maifest file.
public DefaultSamplingStrategy(string samplingRuleManifest)
{
_localFallbackRules = new LocalizedSamplingStrategy(samplingRuleManifest);
InititalizeStrategy();
}
private void InititalizeStrategy()
{
_ruleCache = new RuleCache();
_rulePoller = new RulePoller(_ruleCache);
_targetPoller = new TargetPoller(_ruleCache, _rulePoller);
}
///
/// Start rule poller and target poller.
///
private void Start()
{
lock (_lock)
{
if (!_isPollerStarted)
{
_connector = new ServiceConnector(DaemonCfg, XRayConfig);
_rulePoller.Poll(_connector);
_targetPoller.Poll(_connector);
_isPollerStarted = true;
}
}
}
///
/// Return the matched sampling rule name if the sampler finds one
/// and decide to sample. If no sampling rule matched, it falls back
/// to "ShouldTrace" implementation.
/// All optional arguments are extracted from incoming requests by
/// X-Ray middleware to perform path based sampling.
///
/// Instance of .
/// Instance of .
public SamplingResponse ShouldTrace(SamplingInput input)
{
if (!_isPollerStarted && !AWSXRayRecorder.Instance.IsTracingDisabled()) // Start pollers lazily and only if tracing is not disabled.
{
Start();
}
if (string.IsNullOrEmpty(input.ServiceType))
{
input.ServiceType = AWSXRayRecorder.Instance.Origin;
}
TimeStamp time = TimeStamp.CurrentTime();
SamplingRule sampleRule = _ruleCache.GetMatchedRule(input,time);
if (sampleRule != null)
{
_logger.DebugFormat("Rule {0} is selected to make a sampling decision.", sampleRule.RuleName);
return DefaultSamplingStrategy.ProcessMatchedRule(sampleRule, time);
}
else
{
_logger.InfoFormat("No effective centralized sampling rule match. Fallback to local rules.");
return _localFallbackRules.ShouldTrace(input);
}
}
private static SamplingResponse ProcessMatchedRule(SamplingRule sampleRule, TimeStamp time)
{
bool shouldSample = true;
Reservior reservior = sampleRule.Reservior;
sampleRule.IncrementRequestCount(); // increment request counter for matched rule
ReserviorDecision reserviorDecision = reservior.BorrowOrTake(time, sampleRule.CanBorrow); // check if we can borrow or take from reservior
if (reserviorDecision == ReserviorDecision.Borrow)
{
sampleRule.IncrementBorrowCount();
}
else if (reserviorDecision == ReserviorDecision.Take)
{
sampleRule.IncrementSampledCount();
}
else if (ThreadSafeRandom.NextDouble() <= sampleRule.GetRate()) // compute based on fixed rate
{
sampleRule.IncrementSampledCount();
}
else
{
shouldSample = false;
}
SamplingResponse sampleResult;
if (shouldSample)
{
sampleResult = new SamplingResponse(sampleRule.RuleName, SampleDecision.Sampled);
}
else
{
sampleResult = new SamplingResponse(SampleDecision.NotSampled);
}
return sampleResult;
}
///
/// Configures X-Ray client with given instance.
///
/// An instance of .
public void LoadDaemonConfig(DaemonConfig daemonConfig)
{
DaemonCfg = daemonConfig;
}
}
}