internal DbConnectionStringParser(IApmLogger logger) => _logger = logger.Scoped(ThisClassName);
/// <summary> /// If the logger has a loglevel, which is higher than Info then it returns a MaybeLogger instance, /// otherwise it returns null. /// By using the return value with `?.` you can avoid executing code that is not necessary to execute /// in case the log won't be printed because the loglevel would not allow it. /// </summary> /// <param name="logger">The logger instance you want to log with</param> /// <returns>Either a MaybeLogger or null</returns> internal static MaybeLogger?Info(this IApmLogger logger) => IfLevel(logger, LogLevel.Information);
internal static ScopedLogger Scoped(this IApmLogger logger, string scope) =>
public AzureCloudMetadataProvider(IApmLogger logger) : this(logger, new HttpClientHandler()) { }
internal ConfigStateC(IApmLogger logger) { _logger = logger.Scoped(ThisClassName); _appliedByAgent = new TaskCompletionSource <object>(); }
public Span( string name, string type, string parentId, string traceId, Transaction enclosingTransaction, IPayloadSender payloadSender, IApmLogger logger, ICurrentExecutionSegmentsContainer currentExecutionSegmentsContainer, IApmServerInfo apmServerInfo, Span parentSpan = null, InstrumentationFlag instrumentationFlag = InstrumentationFlag.None, bool captureStackTraceOnStart = false ) { InstrumentationFlag = instrumentationFlag; Timestamp = TimeUtils.TimestampNow(); Id = RandomGenerator.GenerateRandomBytesAsString(new byte[8]); _logger = logger?.Scoped($"{nameof(Span)}.{Id}"); _payloadSender = payloadSender; _currentExecutionSegmentsContainer = currentExecutionSegmentsContainer; _parentSpan = parentSpan; _enclosingTransaction = enclosingTransaction; _apmServerInfo = apmServerInfo; Name = name; Type = type; ParentId = parentId; TraceId = traceId; if (IsSampled) { SampleRate = enclosingTransaction.SampleRate; // Started and dropped spans should be counted only for sampled transactions if (enclosingTransaction.SpanCount.IncrementTotal() > ConfigSnapshot.TransactionMaxSpans && ConfigSnapshot.TransactionMaxSpans >= 0) { _isDropped = true; enclosingTransaction.SpanCount.IncrementDropped(); } else { enclosingTransaction.SpanCount.IncrementStarted(); // In some cases capturing the stacktrace in End() results in a stack trace which is not very useful. // In such cases we capture the stacktrace on span start. // These are typically async calls - e.g. capturing stacktrace for outgoing HTTP requests in the // System.Net.Http.HttpRequestOut.Stop // diagnostic source event produces a stack trace that does not contain the caller method in user code - therefore we // capture the stacktrace is .Start if (captureStackTraceOnStart && ConfigSnapshot.StackTraceLimit != 0 && ConfigSnapshot.SpanFramesMinDurationInMilliseconds != 0) { RawStackTrace = new StackTrace(true); } } } else { SampleRate = 0; } _currentExecutionSegmentsContainer.CurrentSpan = this; _logger.Trace() ?.Log("New Span instance created: {Span}. Start time: {Time} (as timestamp: {Timestamp}). Parent span: {Span}", this, TimeUtils.FormatTimestampForLog(Timestamp), Timestamp, _parentSpan); }
public FullFrameworkConfigReader(IApmLogger logger = null) : base(logger, /* defaultEnvironmentName: */ null, ThisClassName) => _logger = logger?.Scoped(ThisClassName);
public CloudMetadataProviderCollection(string cloudProvider, IApmLogger logger) : this(cloudProvider, logger, new EnvironmentVariables(logger)) { }
internal MockConfigSnapshot BuildConfig(IApmLogger logger) => new MockConfigSnapshot(logger , flushInterval: FlushInterval.HasValue ? $"{FlushInterval.Value.TotalMilliseconds}ms" : null , maxBatchEventCount: MaxBatchEventCount?.ToString() , maxQueueEventCount: MaxQueueEventCount?.ToString());
/// <summary> /// Turns an <see cref="Exception"/> into a <see cref="CapturedStackFrame" /> list which can be reported to the APM Server /// </summary> /// <param name="exception">The exception to rewrite into APM stack traces</param> /// <param name="logger">The logger to emit exceptions on should one occur</param> /// <param name="capturingFor">Just for logging.</param> /// <returns>A prepared List that can be passed to the APM server</returns> internal static List <CapturedStackFrame> GenerateApmStackTrace(Exception exception, IApmLogger logger, string capturingFor) { try { return(GenerateApmStackTrace(new StackTrace(exception, true).GetFrames(), logger, capturingFor)); } catch (Exception e) { logger?.Warning()?.LogException(e, "Failed extracting exception from stackTrace for {ApmContext}", capturingFor); } return(null); }
public EnvironmentVariables(IApmLogger logger) => _logger = logger.Scoped(nameof(EnvironmentVariables));
/// <summary> /// Turns a System.Diagnostic.StackFrame[] into a <see cref="CapturedStackFrame" /> list which can be reported to the APM Server /// </summary> /// <param name="frames">The stack frames to rewrite into APM stack traces</param> /// <param name="logger">The logger to emit exceptions on should one occur</param> /// <param name="capturingFor">Just for logging.</param> /// <returns>A prepared List that can be passed to the APM server</returns> internal static List <CapturedStackFrame> GenerateApmStackTrace(StackFrame[] frames, IApmLogger logger, string capturingFor) { var retVal = new List <CapturedStackFrame>(frames.Length); try { retVal.AddRange(from item in frames let fileName = item?.GetMethod()?.DeclaringType?.Assembly?.GetName()?.Name where !string.IsNullOrEmpty(fileName) select new CapturedStackFrame { Function = item?.GetMethod()?.Name, FileName = fileName, Module = item?.GetMethod()?.ReflectedType?.Name, LineNo = item?.GetFileLineNumber() ?? 0 }); } catch (Exception e) { logger?.Warning()?.LogException(e, "Failed capturing stacktrace for {ApmContext}", capturingFor); } return(retVal); }
internal DbSpanCommon(IApmLogger logger) => _dbConnectionStringParser = new DbConnectionStringParser(logger);
/// <summary> /// Creates a new transaction /// </summary> /// <param name="logger">The logger which logs debug information during the transaction creation process</param> /// <param name="name">The name of the transaction</param> /// <param name="type">The type of the transaction</param> /// <param name="sampler">The sampler implementation which makes the sampling decision</param> /// <param name="distributedTracingData">Distributed tracing data, in case this transaction is part of a distributed trace</param> /// <param name="sender">The IPayloadSender implementation which will record this transaction</param> /// <param name="configSnapshot">The current configuration snapshot which contains the up-do-date config setting values</param> /// <param name="currentExecutionSegmentsContainer" /> /// The ExecutionSegmentsContainer which makes sure this transaction flows /// <param name="apmServerInfo">Component to fetch info about APM Server (e.g. APM Server version)</param> /// <param name="ignoreActivity"> /// If set the transaction will ignore Activity.Current and it's trace id, /// otherwise the agent will try to keep ids in-sync across async work-flows /// </param> internal Transaction( IApmLogger logger, string name, string type, Sampler sampler, DistributedTracingData distributedTracingData, IPayloadSender sender, IConfigSnapshot configSnapshot, ICurrentExecutionSegmentsContainer currentExecutionSegmentsContainer, IApmServerInfo apmServerInfo, bool ignoreActivity = false ) { ConfigSnapshot = configSnapshot; Timestamp = TimeUtils.TimestampNow(); _logger = logger?.Scoped(nameof(Transaction)); _apmServerInfo = apmServerInfo; _sender = sender; _currentExecutionSegmentsContainer = currentExecutionSegmentsContainer; Name = name; HasCustomName = false; Type = type; // For each new transaction, start an Activity if we're not ignoring them. // If Activity.Current is not null, the started activity will be a child activity, // so the traceid and tracestate of the parent will flow to it. if (!ignoreActivity) { _activity = StartActivity(); } var isSamplingFromDistributedTracingData = false; if (distributedTracingData == null) { // We consider a newly created transaction **without** explicitly passed distributed tracing data // to be a root transaction. // Ignore the created activity ActivityTraceFlags because it starts out without setting the IsSampled flag, // so relying on that would mean a transaction is never sampled. if (_activity != null) { // If an activity was created, reuse its id Id = _activity.SpanId.ToHexString(); TraceId = _activity.TraceId.ToHexString(); var idBytesFromActivity = new Span <byte>(new byte[16]); _activity.TraceId.CopyTo(idBytesFromActivity); // Read right most bits. From W3C TraceContext: "it is important for trace-id to carry "uniqueness" and "randomness" // in the right part of the trace-id..." idBytesFromActivity = idBytesFromActivity.Slice(8); _traceState = new TraceState(); // If activity has a tracestate, populate the transaction tracestate with it. if (!string.IsNullOrEmpty(_activity.TraceStateString)) { _traceState.AddTextHeader(_activity.TraceStateString); } IsSampled = sampler.DecideIfToSample(idBytesFromActivity.ToArray()); // In the unlikely event that tracestate populated from activity contains an es vendor key, the tracestate // is mutated to set the sample rate defined by the sampler, because we consider a transaction without // explicitly passed distributedTracingData to be a **root** transaction. The end result // is that activity tracestate will be propagated, along with the sample rate defined by this transaction. if (IsSampled) { SampleRate = sampler.Rate; _traceState.SetSampleRate(sampler.Rate); } else { SampleRate = 0; _traceState.SetSampleRate(0); } // sync the activity tracestate with the tracestate of the transaction _activity.TraceStateString = _traceState.ToTextHeader(); } else { // If no activity is created, create new random ids var idBytes = new byte[8]; Id = RandomGenerator.GenerateRandomBytesAsString(idBytes); IsSampled = sampler.DecideIfToSample(idBytes); idBytes = new byte[16]; TraceId = RandomGenerator.GenerateRandomBytesAsString(idBytes); if (IsSampled) { _traceState = new TraceState(sampler.Rate); SampleRate = sampler.Rate; } else { _traceState = new TraceState(0); SampleRate = 0; } } // ParentId could be also set here, but currently in the UI each trace must start with a transaction where the ParentId is null, // so to avoid https://github.com/elastic/apm-agent-dotnet/issues/883 we don't set it yet. } else { if (_activity != null) { Id = _activity.SpanId.ToHexString(); // try to set the parent id and tracestate on the created activity, based on passed distributed tracing data. // This is so that the distributed tracing data will flow to any child activities try { _activity.SetParentId( ActivityTraceId.CreateFromString(distributedTracingData.TraceId.AsSpan()), ActivitySpanId.CreateFromString(distributedTracingData.ParentId.AsSpan()), distributedTracingData.FlagRecorded ? ActivityTraceFlags.Recorded : ActivityTraceFlags.None); if (distributedTracingData.HasTraceState) { _activity.TraceStateString = distributedTracingData.TraceState.ToTextHeader(); } } catch (Exception e) { _logger.Error()?.LogException(e, "Error setting trace context on created activity"); } } else { var idBytes = new byte[8]; Id = RandomGenerator.GenerateRandomBytesAsString(idBytes); } TraceId = distributedTracingData.TraceId; ParentId = distributedTracingData.ParentId; IsSampled = distributedTracingData.FlagRecorded; isSamplingFromDistributedTracingData = true; _traceState = distributedTracingData.TraceState; // If there is no tracestate or no valid "es" vendor entry with an "s" (sample rate) attribute, then the agent must // omit sample rate from non-root transactions and their spans. // See https://github.com/elastic/apm/blob/master/specs/agents/tracing-sampling.md#propagation if (_traceState?.SampleRate is null) { SampleRate = null; } else { SampleRate = _traceState.SampleRate.Value; } } // Also mark the sampling decision on the Activity if (IsSampled && _activity != null) { _activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded; } SpanCount = new SpanCount(); _currentExecutionSegmentsContainer.CurrentTransaction = this; if (isSamplingFromDistributedTracingData) { _logger.Trace() ?.Log("New Transaction instance created: {Transaction}. " + "IsSampled ({IsSampled}) and SampleRate ({SampleRate}) is based on incoming distributed tracing data ({DistributedTracingData})." + " Start time: {Time} (as timestamp: {Timestamp})", this, IsSampled, SampleRate, distributedTracingData, TimeUtils.FormatTimestampForLog(Timestamp), Timestamp); } else { _logger.Trace() ?.Log("New Transaction instance created: {Transaction}. " + "IsSampled ({IsSampled}) is based on the given sampler ({Sampler})." + " Start time: {Time} (as timestamp: {Timestamp})", this, IsSampled, sampler, TimeUtils.FormatTimestampForLog(Timestamp), Timestamp); } }
internal CentralConfigFetcher(IApmLogger logger, IConfigStore configStore, ICentralConfigResponseParser centralConfigResponseParser, Service service, HttpMessageHandler httpMessageHandler = null, IAgentTimer agentTimer = null, string dbgName = null ) : this(logger, configStore, configStore.CurrentSnapshot, service, httpMessageHandler, agentTimer, dbgName) =>
public PayloadSenderTests(ITestOutputHelper xUnitOutputHelper) : base(xUnitOutputHelper /*, LogLevel.Debug */) { _logger = LoggerBase.Scoped(ThisClassName); // LoggerBase.Level = LogLevel.Debug; }
public TestSystemInfoHelper(IApmLogger logger, string lineInCroup) : base(logger) => _lineInCroup = lineInCroup;
/// <summary> /// Extracts the request body using measure to prevent the 'read once' problem (cannot read after the body ha been already /// read). /// </summary> /// <param name="request"></param> /// <param name="logger"></param> /// <returns></returns> public static async Task <string> ExtractRequestBodyAsync(this HttpRequest request, IApmLogger logger, IConfigSnapshot configSnapshot) { string body = null; try { if (request.HasFormContentType) { var form = await request.ReadFormAsync(); var itemProcessed = 0; if (form != null && form.Count > 0) { var sb = new StringBuilder(); foreach (var item in form) { sb.Append(item.Key); sb.Append("="); if (WildcardMatcher.IsAnyMatch(configSnapshot.SanitizeFieldNames, item.Key)) { sb.Append(Elastic.Apm.Consts.Redacted); } else { sb.Append(item.Value); } itemProcessed++; if (itemProcessed != form.Count) { sb.Append("&"); } } body = sb.ToString(); } } else { request.EnableBuffering(); request.Body.Position = 0; using (var reader = new StreamReader(request.Body, Encoding.UTF8, false, 1024 * 2, true)) body = await reader.ReadToEndAsync(); // Truncate the body to the first 2kb if it's longer if (body.Length > Consts.RequestBodyMaxLength) { body = body.Substring(0, Consts.RequestBodyMaxLength); } request.Body.Position = 0; } } catch (IOException ioException) { logger.Error()?.LogException(ioException, "IO Error reading request body"); } catch (Exception e) { logger.Error()?.LogException(e, "Error reading request body"); } return(body); }
protected AbstractConfigurationReader(IApmLogger logger) => ScopedLogger = logger?.Scoped(GetType().Name);
internal SystemTotalCpuProvider(IApmLogger logger, StreamReader procStatStreamReader) => (_logger, _procStatStreamReader) = (logger.Scoped(nameof(SystemTotalCpuProvider)), procStatStreamReader);
internal AzureCloudMetadataProvider(IApmLogger logger, HttpMessageHandler handler) { _handler = handler; _logger = logger.Scoped(nameof(AzureCloudMetadataProvider)); }
public ScopedLogger(IApmLogger logger, string scope) => (Logger, Scope) = (logger, scope);
public Span(string name, string type, Transaction transaction, IPayloadSender payloadSender, IApmLogger logger) { _start = DateTimeOffset.UtcNow; _payloadSender = payloadSender; _logger = logger?.Scoped(nameof(Span)); Name = name; Type = type; Id = RandomGenerator.GetRandomBytesAsString(new byte[8]); ParentId = transaction.Id; TransactionId = transaction.Id; TraceId = transaction.TraceId; }
protected AbstractConfigurationReader(IApmLogger logger, string dbgDerivedClassName) =>
public SanitizeFieldNamesTests(WebApplicationFactory <Startup> factory) { _logger = new TestLogger(); _factory = factory; }
public SystemInfoHelper(IApmLogger logger) => _logger = logger.Scoped(nameof(SystemInfoHelper));
public MaybeLogger(IApmLogger logger, LogLevel level) => (_logger, _level) = (logger, level);
public MetricsTests(ITestOutputHelper xUnitOutputHelper) : base(xUnitOutputHelper) { _output = xUnitOutputHelper; _logger = LoggerBase.Scoped(ThisClassName); }
/// <summary> /// Depending on the two parameters it either returns a MaybeLogger instance or null. /// </summary> /// <param name="logger">The logger you want to log with</param> /// <param name="level">The level to compare with</param> /// <returns>If the return value is not null you can call <see cref="MaybeLogger.Log" /> to log</returns> private static MaybeLogger?IfLevel(this IApmLogger logger, LogLevel level) => logger.IsEnabled(level) ? new MaybeLogger(logger, level) : (MaybeLogger?)null;
internal static Service GetDefaultService(IConfigurationReader configurationReader, IApmLogger loggerArg) { IApmLogger logger = loggerArg.Scoped(nameof(Service)); return(new Service { Name = configurationReader.ServiceName, Agent = new AgentC { Name = Consts.AgentName, Version = typeof(Agent).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion }, Runtime = PlatformDetection.GetServiceRuntime(logger) }); }