//-----------------------------------------------------------------------------
//
// 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 System;
using System.Collections.Generic;
using Amazon.Runtime.Internal.Util;
using Amazon.XRay.Recorder.Core.Internal.Context;
using Amazon.XRay.Recorder.Core.Internal.Emitters;
using Amazon.XRay.Recorder.Core.Internal.Utils;
using Amazon.XRay.Recorder.Core.Plugins;
using Amazon.XRay.Recorder.Core.Sampling;
using Amazon.XRay.Recorder.Core.Strategies;
namespace Amazon.XRay.Recorder.Core
{
///
/// This class provides utilities to build an instance of with different configurations.
///
public class AWSXRayRecorderBuilder
{
private static readonly Logger _logger = Logger.GetLogger(typeof(AWSXRayRecorderBuilder));
private static readonly char[] _validSeparators = { ' ', ',', ';' };
private static readonly string _pluginNamespace = typeof(IPlugin).Namespace;
private readonly List _plugins = new List();
private ISamplingStrategy _samplingStrategy;
private ContextMissingStrategy _contextMissingStrategy = ContextMissingStrategy.LOG_ERROR;
private ISegmentEmitter _segmentEmitter;
private string _daemonAddress;
private ITraceContext _traceContext;
private ExceptionSerializationStrategy _exceptionSerializationStrategy;
private IStreamingStrategy _streamingStrategy;
///
/// Gets a read-only copy of current plugins in the builder
///
public IReadOnlyList Plugins
{
get
{
return _plugins.AsReadOnly();
}
}
#if NETFRAMEWORK
///
/// Initializes instance with default settings.
///
/// instance of
public static AWSXRayRecorderBuilder GetDefaultBuilder()
{
return new AWSXRayRecorderBuilder().WithPluginsFromAppSettings().WithContextMissingStrategyFromAppSettings();
}
#endif
#if NETFRAMEWORK
///
/// Reads plugin settings from app settings, and adds new instance of each plugin into the builder.
/// If the plugin settings doesn't exist or the value of the settings is invalid, nothing will be added.
///
/// The builder with plugin added.
public AWSXRayRecorderBuilder WithPluginsFromAppSettings()
{
var setting = AppSettings.PluginSetting;
if (string.IsNullOrEmpty(setting))
{
_logger.DebugFormat("Plugin setting is missing.");
return this;
}
PopulatePlugins(setting);
return this;
}
///
/// Reads useRuntimeErrors settings from app settings, and adds into the builder.
/// If the useRuntimeErrors settings doesn't exist, it defaults to false and ContextMissingStrategy.LOG_ERROR is used.
///
/// The builder with context missing strategy set.
public AWSXRayRecorderBuilder WithContextMissingStrategyFromAppSettings()
{
bool useRuntimeErrors = AppSettings.UseRuntimeErrors;
if (useRuntimeErrors)
{
return WithContextMissingStrategy(ContextMissingStrategy.RUNTIME_ERROR);
}
return WithContextMissingStrategy(ContextMissingStrategy.LOG_ERROR);
}
#else
///
/// Builds instance with xrayoptions.
///
/// Instance of
/// Instance of .
public AWSXRayRecorderBuilder WithPluginsFromConfig(XRayOptions xRayOptions)
{
var setting = xRayOptions.PluginSetting;
if (string.IsNullOrEmpty(setting))
{
_logger.DebugFormat("Plugin setting is missing.");
return this;
}
PopulatePlugins(setting);
return this;
}
///
/// Reads useRuntimeErrors settings from config instance, and adds into the builder.
/// If the useRuntimeErrors settings doesn't exist, it defaults to false and ContextMissingStrategy.LOG_ERROR is used.
///
/// The builder with context missing strategy set.
public AWSXRayRecorderBuilder WithContextMissingStrategyFromConfig(XRayOptions xRayOptions)
{
if (xRayOptions.UseRuntimeErrors)
{
return WithContextMissingStrategy(ContextMissingStrategy.RUNTIME_ERROR);
}
else
{
return WithContextMissingStrategy(ContextMissingStrategy.LOG_ERROR);
}
}
///
/// Build a instance of with class.
/// An instance of class.
///
/// A new instance of class.
public AWSXRayRecorder Build(XRayOptions xRayOptions)
{
var recorder = new AWSXRayRecorder(xRayOptions);
PopulateRecorder(recorder);
return recorder;
}
///
/// Configures a instance of with existing configuration added to the builder.
///
/// An instance of .
/// A new instance of .
public AWSXRayRecorder Build(AWSXRayRecorder recorder)
{
PopulateRecorder(recorder);
return recorder;
}
#endif
///
/// Adds the given plugin to builder
///
/// A specific plugin to add.
/// The builder with plugin added.
public AWSXRayRecorderBuilder WithPlugin(IPlugin plugin)
{
if (plugin == null)
{
throw new ArgumentNullException(nameof(plugin));
}
_plugins.Add(plugin);
return this;
}
///
/// Sets the address for the xray daemon.
///
/// The xray daemon address.
/// The builder with the specified xray daemon address.
public AWSXRayRecorderBuilder WithDaemonAddress(String address)
{
if (String.IsNullOrEmpty(address))
{
throw new ArgumentNullException("DaemonAddress");
}
_daemonAddress = address;
return this;
}
///
/// Adds the given sampling strategy to builder. There can exist only one sampling strategy.
/// Any previous value of sampling strategy will be overwritten.
///
/// A sampling strategy to add
/// The builder with sampling strategy added.
public AWSXRayRecorderBuilder WithSamplingStrategy(ISamplingStrategy newStrategy)
{
_samplingStrategy = newStrategy ?? throw new ArgumentNullException("SamplingStrategy");
return this;
}
///
/// Adds the given streaming strategy to builder. There can exist only one streaming strategy.
/// Any previous value of streaming strategy will be overwritten.
///
/// A streaming strategy to add
/// The builder with streaming strategy added
public AWSXRayRecorderBuilder WithStreamingStrategy(IStreamingStrategy newStreamingStrategy)
{
_streamingStrategy = newStreamingStrategy ?? throw new ArgumentNullException("StreamingStrategy");
return this;
}
///
/// Adds the context missing strategy.
///
/// The ContextMissingStrategy.
/// The builder with context missing strategy added.
public AWSXRayRecorderBuilder WithContextMissingStrategy(ContextMissingStrategy strategy)
{
_contextMissingStrategy = strategy;
return this;
}
///
/// Adds the provided instance.
///
/// The provided instance.
/// The builder with ISegmentEmitter added.
public AWSXRayRecorderBuilder WithSegmentEmitter(ISegmentEmitter segmentEmitter)
{
_segmentEmitter = segmentEmitter ?? throw new ArgumentNullException("SegmentEmitter");
return this;
}
///
/// Configures recorder with instance.
///
/// The provided instance.
/// The builder with ITraceContext added.
public AWSXRayRecorderBuilder WithTraceContext(ITraceContext traceContext)
{
_traceContext = traceContext ?? throw new ArgumentNullException("TraceContext");
return this;
}
///
/// Configures recorder with provided . While setting number consider max trace size
/// limit : https://aws.amazon.com/xray/pricing/
///
/// An instance of
/// The builder with exception serialization strategy added.
public AWSXRayRecorderBuilder WithExceptionSerializationStrategy(ExceptionSerializationStrategy exceptionSerializationStartegy)
{
_exceptionSerializationStrategy = exceptionSerializationStartegy ?? throw new ArgumentNullException("ExceptionSerializationStartegy"); ;
return this;
}
///
/// Build a instance of with existing configuration added to the builder.
///
/// A new instance of .
public AWSXRayRecorder Build()
{
var recorder = new AWSXRayRecorder();
PopulateRecorder(recorder);
return recorder;
}
private void PopulatePlugins(string setting)
{
var pluginSettings = setting.Split(_validSeparators, StringSplitOptions.RemoveEmptyEntries);
foreach (string pluginSetting in pluginSettings)
{
string fullTypeName = _pluginNamespace + "." + pluginSetting;
var type = Type.GetType(fullTypeName);
if (type == null)
{
_logger.DebugFormat("Invalid plugin setting: {0}", pluginSetting);
continue;
}
try
{
var plugin = Activator.CreateInstance(type) as IPlugin;
if (plugin == null)
{
_logger.DebugFormat("Failed to create an instance of type: {0}", type.FullName);
continue;
}
_plugins.Add(plugin);
}
catch (MissingMethodException e)
{
_logger.Debug(e, "Failed to create the plugin: {0}", type.FullName);
}
}
}
private void PopulateRecorder(AWSXRayRecorder recorder)
{
foreach (IPlugin plugin in _plugins)
{
if (plugin.TryGetRuntimeContext(out IDictionary pluginContext))
{
recorder.RuntimeContext.Add(plugin.ServiceName, pluginContext);
recorder.Origin = plugin.Origin;
}
}
recorder.ContextMissingStrategy = _contextMissingStrategy;
if (_segmentEmitter != null)
{
recorder.Emitter = _segmentEmitter;
}
if (_samplingStrategy != null)
{
recorder.SamplingStrategy = _samplingStrategy;
}
if (_streamingStrategy != null)
{
recorder.StreamingStrategy = _streamingStrategy;
}
if (_daemonAddress != null)
{
recorder.SetDaemonAddress(_daemonAddress);
}
if (_traceContext != null)
{
recorder.SetTraceContext(_traceContext);
}
if (_exceptionSerializationStrategy != null)
{
recorder.SetExceptionSerializationStrategy(_exceptionSerializationStrategy);
}
}
}
}