//----------------------------------------------------------------------------- // // 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); } } } }