Пример #1
0
        internal void CollectAllMetrics()
        {
            using var acq = _isCollectionInProgress.TryAcquireWithDisposable();
            if (!acq.IsAcquired)
            {
                _logger.Trace()?.Log("Previous CollectAllMetrics call is still in progress - skipping this one");
                return;
            }

            if (!_configSnapshotProvider.CurrentSnapshot.Recording)
            {
                //We only handle the Recording=false here. If Enabled=false, then the MetricsCollector is not started at all.
                _logger.Trace()?.Log("Skip collecting metrics - Recording is set to false");
                return;
            }

            try
            {
                CollectAllMetricsImpl();
            }
            catch (Exception e)
            {
                _logger.Error()
                ?.LogExceptionWithCaller(e);
            }
        }
Пример #2
0
        internal static Runtime GetServiceRuntime(IApmLogger logger)
        {
            string name;

            if (IsDotNetFullFramework)
            {
                name = Runtime.DotNetFullFrameworkName;
            }
            else if (IsDotNetCore)
            {
                name = Runtime.DotNetCoreName;
            }
            else if (IsMono)
            {
                name = Runtime.MonoName;
            }
            else
            {
                name = "N/A";
                logger.Error()
                ?.Log("Failed to detect whether the current .NET runtime is .NET Full Framework, Mono or .NET Core - " +
                      "`{DotNetFrameworkRuntimeName}' will be used as the current .NET runtime name", name);
            }

            string version;

            try
            {
                if (IsDotNetFullFramework)
                {
                    version = typeof(object).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion;
                }
                else if (IsDotNetCore)
                {
                    version = GetDotNetCoreRuntimeVersion(logger);
                }
                else if (IsMono)
                {
                    version = GetMonoVersion(logger);
                }
                else
                {
                    version = "N/A";
                    logger.Error()
                    ?.Log("Failed to detect whether the current .NET runtime is .NET Full Framework or .NET Core - " +
                          "`{DotNetFrameworkRuntimeVersion}' will be used as the current .NET runtime version", version);
                }
            }
            catch (Exception ex)
            {
                version = "N/A";
                logger.Error()
                ?.LogException(ex, "Exception was thrown while trying to obtain .NET runtime version" +
                               " - `{DotNetFrameworkRuntimeVersion}' will be used", version);
            }

            return(new Runtime {
                Name = name, Version = version
            });
        }
Пример #3
0
        /// <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)
        {
            string body = null;

            try
            {
                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);
        }
Пример #4
0
        /// <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 string ExtractRequestBody(this HttpRequest request, IApmLogger logger)
        {
            string body = null;

            try
            {
                request.EnableRewind();
                request.Body.Position = 0;

                using (var reader = new StreamReader(request.Body,
                                                     encoding: Encoding.UTF8,
                                                     detectEncodingFromByteOrderMarks: false,
                                                     bufferSize: 1024 * 2,
                                                     leaveOpen: true))
                {
                    body = reader.ReadToEnd();
                    // 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);
        }
        private Transaction StartTransactionAsync(HttpContext context)
        {
            try
            {
                if (WildcardMatcher.IsAnyMatch(_configurationReader.TransactionIgnoreUrls, context.Request.Path))
                {
                    _logger.Debug()?.Log("Request ignored based on TransactionIgnoreUrls, url: {urlPath}", context.Request.Path);
                    return(null);
                }

                Transaction transaction;
                var         transactionName = $"{context.Request.Method} {context.Request.Path}";

                if (context.Request.Headers.ContainsKey(TraceContext.TraceParentHeaderNamePrefixed) ||
                    context.Request.Headers.ContainsKey(TraceContext.TraceParentHeaderName))
                {
                    var headerValue = context.Request.Headers.ContainsKey(TraceContext.TraceParentHeaderName)
                                                ? context.Request.Headers[TraceContext.TraceParentHeaderName].ToString()
                                                : context.Request.Headers[TraceContext.TraceParentHeaderNamePrefixed].ToString();

                    var tracingData = context.Request.Headers.ContainsKey(TraceContext.TraceStateHeaderName)
                                                ? TraceContext.TryExtractTracingData(headerValue, context.Request.Headers[TraceContext.TraceStateHeaderName].ToString())
                                                : TraceContext.TryExtractTracingData(headerValue);

                    if (tracingData != null)
                    {
                        _logger.Debug()
                        ?.Log(
                            "Incoming request with {TraceParentHeaderName} header. DistributedTracingData: {DistributedTracingData}. Continuing trace.",
                            TraceContext.TraceParentHeaderNamePrefixed, tracingData);

                        transaction = _tracer.StartTransactionInternal(transactionName, ApiConstants.TypeRequest, tracingData);
                    }
                    else
                    {
                        _logger.Debug()
                        ?.Log(
                            "Incoming request with invalid {TraceParentHeaderName} header (received value: {TraceParentHeaderValue}). Starting trace with new trace id.",
                            TraceContext.TraceParentHeaderNamePrefixed, headerValue);

                        transaction = _tracer.StartTransactionInternal(transactionName, ApiConstants.TypeRequest);
                    }
                }
                else
                {
                    _logger.Debug()?.Log("Incoming request. Starting Trace.");
                    transaction = _tracer.StartTransactionInternal(transactionName, ApiConstants.TypeRequest);
                }

                return(transaction);
            }
            catch (Exception ex)
            {
                _logger?.Error()?.LogException(ex, "Exception thrown while trying to start transaction");
                return(null);
            }
        }
Пример #6
0
        private Transaction StartTransaction(HttpContext context)
        {
            try
            {
                Transaction transaction;
                var         transactionName = $"{context.Request.Method} {context.Request.Path}";

                if (context.Request.Headers.ContainsKey(TraceParent.TraceParentHeaderName))
                {
                    var headerValue = context.Request.Headers[TraceParent.TraceParentHeaderName].ToString();

                    var distributedTracingData = TraceParent.TryExtractTraceparent(headerValue);

                    if (distributedTracingData != null)
                    {
                        _logger.Debug()
                        ?.Log(
                            "Incoming request with {TraceParentHeaderName} header. DistributedTracingData: {DistributedTracingData}. Continuing trace.",
                            TraceParent.TraceParentHeaderName, distributedTracingData);

                        transaction = _tracer.StartTransactionInternal(
                            transactionName,
                            ApiConstants.TypeRequest,
                            distributedTracingData);
                    }
                    else
                    {
                        _logger.Debug()
                        ?.Log(
                            "Incoming request with invalid {TraceParentHeaderName} header (received value: {TraceParentHeaderValue}). Starting trace with new trace id.",
                            TraceParent.TraceParentHeaderName, headerValue);

                        transaction = _tracer.StartTransactionInternal(transactionName,
                                                                       ApiConstants.TypeRequest);
                    }
                }
                else
                {
                    _logger.Debug()?.Log("Incoming request. Starting Trace.");
                    transaction = _tracer.StartTransactionInternal(transactionName,
                                                                   ApiConstants.TypeRequest);
                }

                if (transaction.IsSampled)
                {
                    FillSampledTransactionContextRequest(context, transaction);
                }

                return(transaction);
            }
            catch (Exception ex)
            {
                _logger?.Error()?.LogException(ex, "Exception thrown while trying to start transaction");
                return(null);
            }
        }
        public SystemTotalCpuProvider(IApmLogger logger)
        {
            _logger = logger.Scoped(nameof(SystemTotalCpuProvider));
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                var categoryName = "Processor";
                try
                {
                    try
                    {
                        _processorTimePerfCounter = new PerformanceCounter(categoryName, "% Processor Time", "_Total");
                    }
                    catch (InvalidOperationException e)
                    {
                        _logger.Debug()?.LogException(e, "Error instantiating '{CategoryName}' performance counter.", categoryName);
                        _processorTimePerfCounter?.Dispose();
                        // If the Processor performance counter category does not exist, try Processor Information.
                        categoryName = "Processor Information";
                        _processorTimePerfCounter = new PerformanceCounter(categoryName, "% Processor Time", "_Total");
                    }

                    //The perf. counter API returns 0 the for the 1. call (probably because there is no delta in the 1. call) - so we just call it here first
                    _processorTimePerfCounter.NextValue();
                }
                catch (Exception e)
                {
                    if (e is UnauthorizedAccessException)
                    {
                        _logger.Error()
                        ?.LogException(e, "Error instantiating '{CategoryName}' performance counter."
                                       + " Process does not have permissions to read performance counters."
                                       + " See https://www.elastic.co/guide/en/apm/agent/dotnet/current/metrics.html#metrics-system to see how to configure.", categoryName);
                    }
                    else
                    {
                        _logger.Error()
                        ?.LogException(e, "Error instantiating '{CategoryName}' performance counter", categoryName);
                    }

                    _logger.Warning()?.Log("System metrics won't be collected");
                    _processorTimePerfCounter?.Dispose();
                    _processorTimePerfCounter = null;
                }
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                var(success, idle, total) = ReadProcStat();
                if (!success)
                {
                    return;
                }

                _prevIdleTime  = idle;
                _prevTotalTime = total;
            }
        }
 private string FindAppPoolName()
 {
     try
     {
         return(ReadEnvVarValue("APP_POOL_ID"));
     }
     catch (Exception ex)
     {
         _logger.Error()?.Log("Failed to get app pool name: {Exception}", ex);
         return(null);
     }
 }
Пример #9
0
        private async Task <HttpResponseMessage> SendGetRequestToSampleAppAndVerifyResponseImpl(
            HttpRequestMessage httpRequestMessage,
            int expectedStatusCode
            )
        {
            var url = httpRequestMessage.RequestUri;

            _logger.Debug()?.Log("Sending request with URL: {url} and expected status code: {HttpStatusCode}...", url, expectedStatusCode);
            var response = await HttpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);

            _logger.Debug()
            ?.Log("Request sent. Actual status code: {HttpStatusCode} ({HttpStatusCodeEnum})",
                  (int)response.StatusCode, response.StatusCode);
            try
            {
                response.StatusCode.Should().Be(expectedStatusCode);
            }
            catch (XunitException ex)
            {
                var responseContent = await response.Content.ReadAsStringAsync();

                _logger.Error()?.Log("{ExceptionMessage}. Response content:\n{ResponseContent}", ex.Message, responseContent);
                throw;
            }

            var processIdInResponse = response.Headers.GetValues(AspNetFullFrameworkSampleApp.Consts.ProcessIdResponseHeaderName);

            _logger.Debug()
            ?.Log("{ProcessIdHeaderName} in response is {ProcessIdHeaderValue}",
                  AspNetFullFrameworkSampleApp.Consts.ProcessIdResponseHeaderName, processIdInResponse);

            var apmServerUrlsInResponse =
                response.Headers?.GetValues(AspNetFullFrameworkSampleApp.Consts.ElasticApmServerUrlsResponseHeaderName).ToList();

            try
            {
                apmServerUrlsInResponse.Should().HaveCount(1);
                apmServerUrlsInResponse.First().Should().Be(BuildApmServerUrl(_mockApmServerPort));
            }
            catch (XunitException ex)
            {
                _logger.Error()
                ?.LogException(ex, "Sample application's APM-server-URLs configuration setting ({ActualApmServerUrl})" +
                               " is different from expected ({ExpectedApmServerUrl})",
                               string.Join(", ", apmServerUrlsInResponse), BuildApmServerUrl(_mockApmServerPort));

                await PostTestFailureDiagnostics();

                throw;
            }

            return(response);
        }
Пример #10
0
        /// <summary>
        /// Gets the ASP.NET engine version
        /// </summary>
        /// <param name="logger">The logger</param>
        /// <returns>the engine version, or N/A if it cannot be found</returns>
        public static string GetEngineVersion(IApmLogger logger)
        {
            var aspNetVersion = "N/A";

            try
            {
                // We would like to report the same ASP.NET version as the one printed at the bottom of the error page
                // (see https://github.com/microsoft/referencesource/blob/master/System.Web/ErrorFormatter.cs#L431)
                // It is stored in VersionInfo.EngineVersion
                // (see https://github.com/microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System.Web/Util/versioninfo.cs#L91)
                // which is unfortunately an internal property of an internal class in System.Web assembly so we use reflection to get it
                const string versionInfoTypeName = "System.Web.Util.VersionInfo";
                var          versionInfoType     = typeof(HttpRuntime).Assembly.GetType(versionInfoTypeName);
                if (versionInfoType == null)
                {
                    logger.Error()
                    ?.Log("Type {TypeName} was not found in assembly {AssemblyFullName} - {AspNetVersion} will be used as ASP.NET version",
                          versionInfoTypeName, typeof(HttpRuntime).Assembly.FullName, aspNetVersion);
                    return(aspNetVersion);
                }

                const string engineVersionPropertyName = "EngineVersion";
                var          engineVersionProperty     = versionInfoType.GetProperty(engineVersionPropertyName,
                                                                                     BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                if (engineVersionProperty == null)
                {
                    logger.Error()
                    ?.Log("Property {PropertyName} was not found in type {TypeName} - {AspNetVersion} will be used as ASP.NET version",
                          engineVersionPropertyName, versionInfoType.FullName, aspNetVersion);
                    return(aspNetVersion);
                }

                var engineVersionPropertyValue = (string)engineVersionProperty.GetValue(null);
                if (engineVersionPropertyValue == null)
                {
                    logger.Error()
                    ?.Log("Property {PropertyName} (in type {TypeName}) is of type {TypeName} and not a string as expected" +
                          " - {AspNetVersion} will be used as ASP.NET version",
                          engineVersionPropertyName, versionInfoType.FullName, engineVersionPropertyName.GetType().FullName, aspNetVersion);
                    return(aspNetVersion);
                }

                aspNetVersion = engineVersionPropertyValue;
            }
            catch (Exception ex)
            {
                logger.Error()?.LogException(ex, "Failed to obtain ASP.NET version - {AspNetVersion} will be used as ASP.NET version", aspNetVersion);
            }

            logger.Debug()?.Log("Found ASP.NET version: {AspNetVersion}", aspNetVersion);
            return(aspNetVersion);
        }
Пример #11
0
 internal void StartSpan <TResult>(IDbCommand command, DbCommandInterceptionContext <TResult> interceptCtx
                                   , [CallerMemberName] string dbgCaller = null
                                   )
 {
     try
     {
         DoStartSpan(command, interceptCtx, dbgCaller);
     }
     catch (Exception ex)
     {
         _logger.Error()?.LogException(ex, "Processing of DB-operation-started event failed");
     }
 }
Пример #12
0
        private void OnBeginRequest(object eventSender, EventArgs eventArgs)
        {
            Logger.Debug()?.Log("Incoming request processing started - starting trace");

            try
            {
                ProcessBeginRequest(eventSender);
            }
            catch (Exception ex)
            {
                Logger.Error()?.Log("Processing BeginRequest event failed. Exception: {Exception}", ex);
            }
        }
Пример #13
0
        private void EnsureNoRunningWorkerProcesses(ServerManager serverManager)
        {
            var workerProcessIds = GetSampleAppWorkerProcessIds(serverManager);

            _logger.Debug()
            ?.Log("After stopping application pool found {NumberOfWorkerProcesses} worker processes." +
                  " Their PIDs: {WorkerProcessesPIDs}", workerProcessIds.Count, string.Join(", ", workerProcessIds));

            foreach (var workerProcessPid in workerProcessIds)
            {
                Process workerProcess;
                try
                {
                    workerProcess = Process.GetProcessById(workerProcessPid);
                }
                catch (ArgumentException ex)
                {
                    _logger.Debug()?.LogException(ex, "Worker process with PID {WorkerProcessPID} has already exited", workerProcessPid);
                    continue;
                }

                using (workerProcess)
                {
                    _logger.Info()?.Log("About to kill worker process with PID {WorkerProcessPID}...", workerProcessPid);
                    try
                    {
                        workerProcess.Kill();
                    }
                    catch (Exception ex)
                    {
                        _logger.Debug()
                        ?.LogException(ex, "Attempt to kill worker process with PID {WorkerProcessPID} has thrown exception" +
                                       " - maybe process has already exited?", workerProcessPid);
                    }
                    const int maxWaitMs = 10 * 1000;                     // 10 seconds
                    _logger.Info()
                    ?.Log("Waiting for worker process with PID {WorkerProcessPID} to exit... Max wait time: {MaxWaitTimeMs}ms",
                          workerProcessPid, maxWaitMs);
                    var hasProcessExited = workerProcess.WaitForExit(maxWaitMs);
                    if (hasProcessExited)
                    {
                        _logger.Info()?.Log("Worker process with PID {WorkerProcessPID} has exited", workerProcessPid);
                    }
                    else
                    {
                        _logger.Error()?.Log("Worker process with PID {WorkerProcessPID} has NOT exited during wait", workerProcessPid);
                        throw new InvalidOperationException($"Failed to stop IIS worker process with PID {workerProcessPid}");
                    }
                }
            }
        }
Пример #14
0
        private async Task ProcessQueueItems(object[] queueItems)
        {
            try
            {
                var metadataJson = _payloadItemSerializer.SerializeObject(_metadata);
                var ndjson       = new StringBuilder();
                ndjson.AppendLine("{\"metadata\": " + metadataJson + "}");

                foreach (var item in queueItems)
                {
                    var serialized = _payloadItemSerializer.SerializeObject(item);
                    switch (item)
                    {
                    case Transaction _:
                        ndjson.AppendLine("{\"transaction\": " + serialized + "}");
                        break;

                    case Span _:
                        ndjson.AppendLine("{\"span\": " + serialized + "}");
                        break;

                    case Error _:
                        ndjson.AppendLine("{\"error\": " + serialized + "}");
                        break;

                    case MetricSet _:
                        ndjson.AppendLine("{\"metricset\": " + serialized + "}");
                        break;
                    }
                    _logger?.Trace()?.Log("Serialized item to send: {ItemToSend} as {SerializedItem}", item, serialized);
                }

                var content = new StringContent(ndjson.ToString(), Encoding.UTF8, "application/x-ndjson");

                var result = await _httpClient.PostAsync(Consts.IntakeV2Events, content, _cancellationTokenSource.Token);

                if (result != null && !result.IsSuccessStatusCode)
                {
                    _logger?.Error()
                    ?.Log("Failed sending event. " +
                          "APM Server response: status code: {ApmServerResponseStatusCode}, content: \n{ApmServerResponseContent}",
                          result.StatusCode, await result.Content.ReadAsStringAsync());
                }
                else
                {
                    _logger?.Debug()
                    ?.Log("Sent items to server:\n{SerializedItems}",
                          TextUtils.Indent(string.Join($",{Environment.NewLine}", queueItems.ToArray())));
                }
            }
            catch (Exception e)
            {
                _logger?.Warning()
                ?.LogException(
                    e,
                    "Failed sending events. Following events were not transferred successfully to the server ({ApmServerUrl}):\n{SerializedItems}",
                    _httpClient.BaseAddress,
                    TextUtils.Indent(string.Join($",{Environment.NewLine}", queueItems.ToArray())));
            }
        }
Пример #15
0
        private static void FillSampledTransactionContextUser(HttpContext context, Transaction transaction, IApmLogger logger)
        {
            try
            {
                if (context.User?.Identity != null && context.User.Identity.IsAuthenticated && transaction.Context.User == null)
                {
                    transaction.Context.User = new User
                    {
                        UserName = context.User.Identity.Name,
                        Id       = GetClaimWithFallbackValue(ClaimTypes.NameIdentifier, Consts.OpenIdClaimTypes.UserId),
                        Email    = GetClaimWithFallbackValue(ClaimTypes.Email, Consts.OpenIdClaimTypes.Email)
                    };

                    logger.Debug()?.Log("Captured user - {CapturedUser}", transaction.Context.User);
                }
            }
            catch (Exception ex)
            {
                // context.user is optional: https://github.com/elastic/apm-server/blob/64a4ab96ba138050fe496b17d31deb2cf8830deb/docs/spec/user.json#L5
                logger?.Error()
                ?.LogException(ex, "Exception thrown while trying to fill user context for sampled transaction {TransactionId}",
                               transaction.Id);
            }

            string GetClaimWithFallbackValue(string claimType, string fallbackClaimType)
            {
                var idClaims   = context.User.Claims.Where(n => n.Type == claimType || n.Type == fallbackClaimType);
                var enumerable = idClaims.ToList();

                return(enumerable.Any() ? enumerable.First().Value : string.Empty);
            }
        }
Пример #16
0
 private void HandleStartCommand(object payloadData, PropertyFetcherSet propertyFetcherSet)
 {
     try
     {
         if (propertyFetcherSet.StartCorrelationId.Fetch(payloadData) is Guid operationId &&
             propertyFetcherSet.StartCommand.Fetch(payloadData) is IDbCommand dbCommand)
         {
             var span = _apmAgent.TracerInternal.DbSpanCommon.StartSpan(_apmAgent, dbCommand);
             _spans.TryAdd(operationId, span);
         }
     }
     catch (Exception ex)
     {
         //ignore
         _logger.Error()?.LogException(ex, "Exception was thrown while handling 'command started event'");
     }
 }
Пример #17
0
        protected override ConfigurationKeyValue Read(string key, string fallBackEnvVarName)
        {
            try
            {
                var value = ConfigurationManager.AppSettings[key];
                if (value != null)
                {
                    return(Kv(key, value, Origin));
                }
            }
            catch (ConfigurationErrorsException ex)
            {
                _logger.Error()?.LogException(ex, "Exception thrown from ConfigurationManager.AppSettings - falling back on environment variables");
            }

            return(Kv(fallBackEnvVarName, ReadEnvVarValue(fallBackEnvVarName), EnvironmentConfigurationReader.Origin));
        }
        internal static void StopTransaction(Transaction transaction, HttpContext context, IApmLogger logger)
        {
            if (transaction == null)
            {
                return;
            }

            try
            {
                if (!transaction.HasCustomName)
                {
                    //fixup Transaction.Name - e.g. /user/profile/1 -> /user/profile/{id}
                    var routeData = context.GetRouteData()?.Values;

                    if (routeData != null && context.Response.StatusCode != StatusCodes.Status404NotFound)
                    {
                        logger?.Trace()?.Log("Calculating transaction name based on route data");
                        var name = GetNameFromRouteContext(routeData);

                        if (!string.IsNullOrWhiteSpace(name))
                        {
                            transaction.Name = $"{context.Request.Method} {name}";
                        }
                    }
                    else if (context.Response.StatusCode == StatusCodes.Status404NotFound)
                    {
                        logger?.Trace()?
                        .Log("No route data found or status code is 404 - setting transaction name to 'unknown route");
                        transaction.Name = $"{context.Request.Method} unknown route";
                    }
                }

                transaction.Result = Transaction.StatusCodeToResult(GetProtocolName(context.Request.Protocol), context.Response.StatusCode);

                if (context.Response.StatusCode >= 500)
                {
                    transaction.Outcome = Outcome.Failure;
                }
                else
                {
                    transaction.Outcome = Outcome.Success;
                }

                if (transaction.IsSampled)
                {
                    FillSampledTransactionContextResponse(context, transaction, logger);
                    FillSampledTransactionContextUser(context, transaction, logger);
                }
            }
            catch (Exception ex)
            {
                logger?.Error()?.LogException(ex, "Exception thrown while trying to stop transaction");
            }
            finally
            {
                transaction.End();
            }
        }
Пример #19
0
        internal void CollectAllMetrics()
        {
            using (var acq = _isCollectionInProgress.TryAcquireWithDisposable())
            {
                if (!acq.IsAcquired)
                {
                    _logger.Trace()?.Log("Previous CollectAllMetrics call is still in progress - skipping this one");
                    return;
                }

                try
                {
                    CollectAllMetricsImpl();
                }
                catch (Exception e)
                {
                    _logger.Error()
                    ?.LogExceptionWithCaller(e);
                }
            }
        }
 public IActionResult Get() => _mockApmServer.DoUnderLock(() =>
 {
     try
     {
         return(GetImpl());
     }
     catch (Exception ex)
     {
         _logger.Error()?.LogException(ex, nameof(GetImpl) + " has thrown exception");
         throw;
     }
 });
Пример #21
0
        private async Task ProcessQueueItems(object[] queueItems)
        {
            try
            {
                var metadata = new Metadata {
                    Service = _service
                };
                var metadataJson = _payloadItemSerializer.SerializeObject(metadata);
                var ndjson       = new StringBuilder();
                ndjson.Append("{\"metadata\": " + metadataJson + "}" + "\n");

                foreach (var item in queueItems)
                {
                    var serialized = _payloadItemSerializer.SerializeObject(item);
                    switch (item)
                    {
                    case Transaction _:
                        ndjson.AppendLine("{\"transaction\": " + serialized + "}");
                        break;

                    case Span _:
                        ndjson.AppendLine("{\"span\": " + serialized + "}");
                        break;

                    case Error _:
                        ndjson.AppendLine("{\"error\": " + serialized + "}");
                        break;
                    }
                    _logger?.Trace()?.Log("Serialized item to send: {ItemToSend} as {SerializedItemToSend}", item, serialized);
                }

                var content = new StringContent(ndjson.ToString(), Encoding.UTF8, "application/x-ndjson");

                var result = await _httpClient.PostAsync(Consts.IntakeV2Events, content);

                if (result != null && !result.IsSuccessStatusCode)
                {
                    _logger?.Error()?.Log("Failed sending event. {ApmServerResponse}", await result.Content.ReadAsStringAsync());
                }
                else
                {
                    _logger?.Debug()
                    ?.Log($"Sent items to server: {Environment.NewLine}{{items}}", string.Join($",{Environment.NewLine}", queueItems.ToArray()));
                }
            }
            catch (Exception e)
            {
                _logger?.Warning()
                ?.LogException(
                    e, "Failed sending events. Following events were not transferred successfully to the server:\n{items}",
                    string.Join($",{Environment.NewLine}", queueItems.ToArray()));
            }
        }
Пример #22
0
        private void EndProfilingSession(object sender, ProfilingSession session)
        {
            IExecutionSegment executionSegment = sender as Span;
            string            segmentType;

            if (executionSegment is null)
            {
                executionSegment = sender as Transaction;
                if (executionSegment is null)
                {
                    return;
                }

                segmentType = "transaction";
            }
            else
            {
                segmentType = "span";
            }

            try
            {
                // Remove the session. Use session passed to EndProfilingSession rather than the removed session in the event
                // there was an issue in adding or removing the session
                if (!_executionSegmentSessions.TryRemove(executionSegment.Id, out _))
                {
                    _logger.Debug()?.Log(
                        "could not remove profiling session from tracked sessions for {ExecutionSegment} {Id}",
                        segmentType, executionSegment.Id);
                }

                var profiledCommands = session.FinishProfiling();
                _logger.Trace()?.Log(
                    "Finished profiling session for {ExecutionSegment}. Collected {ProfiledCommandCount} commands",
                    executionSegment, profiledCommands.Count());

                foreach (var profiledCommand in profiledCommands)
                {
                    ProcessCommand(profiledCommand, executionSegment);
                }

                _logger.Trace()?.Log(
                    "End profiling session for {ExecutionSegment} {Id}",
                    segmentType, executionSegment.Id);
            }
            catch (Exception e)
            {
                _logger.Error()?.LogException(e,
                                              "Exception ending profiling session for {ExecutionSegment} {Id}",
                                              segmentType, executionSegment.Id);
            }
        }
Пример #23
0
        /// <summary>
        /// Extracts the soap action from the header if exists only with Soap 1.1
        /// </summary>
        /// <param name="headers">The request headers</param>
        /// <param name="requestStream">The request stream</param>
        /// <param name="logger">The logger.</param>
        public static string ExtractSoapAction(NameValueCollection headers, Stream requestStream, IApmLogger logger)
        {
            try
            {
                return(GetSoap11Action(headers) ?? GetSoap12Action(headers, requestStream));
            }
            catch (Exception e)
            {
                logger.Error()?.LogException(e, "Error reading soap action header");
            }

            return(null);
        }
Пример #24
0
        public PayloadSenderV2(IApmLogger logger, IConfigSnapshot config, Service service, Api.System system,
                               HttpMessageHandler httpMessageHandler = null, string dbgName = null
                               )
            : base(/* isEnabled: */ true, logger, ThisClassName, service, config, httpMessageHandler)
        {
            _logger = logger?.Scoped(ThisClassName + (dbgName == null ? "" : $" (dbgName: `{dbgName}')"));
            _payloadItemSerializer = new PayloadItemSerializer(config);

            _intakeV2EventsAbsoluteUrl = BackendCommUtils.ApmServerEndpoints.BuildIntakeV2EventsAbsoluteUrl(config.ServerUrls.First());

            System = system;

            _metadata = new Metadata {
                Service = service, System = System
            };
            foreach (var globalLabelKeyValue in config.GlobalLabels)
            {
                _metadata.Labels.Add(globalLabelKeyValue.Key, globalLabelKeyValue.Value);
            }

            if (config.MaxQueueEventCount < config.MaxBatchEventCount)
            {
                _logger?.Error()
                ?.Log(
                    "MaxQueueEventCount is less than MaxBatchEventCount - using MaxBatchEventCount as MaxQueueEventCount."
                    + " MaxQueueEventCount: {MaxQueueEventCount}."
                    + " MaxBatchEventCount: {MaxBatchEventCount}.",
                    config.MaxQueueEventCount, config.MaxBatchEventCount);

                _maxQueueEventCount = config.MaxBatchEventCount;
            }
            else
            {
                _maxQueueEventCount = config.MaxQueueEventCount;
            }

            _flushInterval = config.FlushInterval;

            _logger?.Debug()
            ?.Log(
                "Using the following configuration options:"
                + " Events intake API absolute URL: {EventsIntakeAbsoluteUrl}"
                + ", FlushInterval: {FlushInterval}"
                + ", MaxBatchEventCount: {MaxBatchEventCount}"
                + ", MaxQueueEventCount: {MaxQueueEventCount}"
                , _intakeV2EventsAbsoluteUrl, _flushInterval.ToHms(), config.MaxBatchEventCount, _maxQueueEventCount);

            _eventQueue = new BatchBlock <object>(config.MaxBatchEventCount);
            TransactionFilters.Add(new TransactionIgnoreUrlsFilter(config).Filter);
            StartWorkLoop();
        }
Пример #25
0
        internal AgentComponents(
            IApmLogger logger,
            IConfigurationReader configurationReader,
            IPayloadSender payloadSender,
            IMetricsCollector metricsCollector,
            ICurrentExecutionSegmentsContainer currentExecutionSegmentsContainer,
            ICentralConfigFetcher centralConfigFetcher,
            IApmServerInfo apmServerInfo
            )
        {
            try
            {
                var tempLogger = logger ?? ConsoleLogger.LoggerOrDefault(configurationReader?.LogLevel);
                ConfigurationReader = configurationReader ?? new EnvironmentConfigurationReader(tempLogger);
                Logger  = logger ?? ConsoleLogger.LoggerOrDefault(ConfigurationReader.LogLevel);
                Service = Service.GetDefaultService(ConfigurationReader, Logger);

                var systemInfoHelper = new SystemInfoHelper(Logger);
                var system           = systemInfoHelper.ParseSystemInfo(ConfigurationReader.HostName);

                ConfigStore = new ConfigStore(new ConfigSnapshotFromReader(ConfigurationReader, "local"), Logger);

                ApmServerInfo = apmServerInfo ?? new ApmServerInfo();

                PayloadSender = payloadSender
                                ?? new PayloadSenderV2(Logger, ConfigStore.CurrentSnapshot, Service, system, ApmServerInfo,
                                                       isEnabled: ConfigurationReader.Enabled);

                HttpTraceConfiguration = new HttpTraceConfiguration();

                if (ConfigurationReader.Enabled)
                {
                    CentralConfigFetcher = centralConfigFetcher ?? new CentralConfigFetcher(Logger, ConfigStore, Service);
                    MetricsCollector     = metricsCollector ?? new MetricsCollector(Logger, PayloadSender, ConfigStore);
                    MetricsCollector.StartCollecting();
                }

                TracerInternal = new Tracer(Logger, Service, PayloadSender, ConfigStore,
                                            currentExecutionSegmentsContainer ?? new CurrentExecutionSegmentsContainer(), ApmServerInfo);

                if (!ConfigurationReader.Enabled)
                {
                    Logger?.Info()?.Log("The Elastic APM .NET Agent is disabled - the agent won't capture traces and metrics.");
                }
            }
            catch (Exception e)
            {
                logger?.Error()?.LogException(e, "Failed initializing agent.");
            }
        }
Пример #26
0
        public ProcessTotalCpuTimeProvider(IApmLogger logger)
        {
            IApmLogger loggerInCtor = logger.Scoped(nameof(ProcessTotalCpuTimeProvider));

            try
            {
                _lastTimeWindowStart       = DateTime.UtcNow;
                _lastCurrentProcessCpuTime = Process.GetCurrentProcess().TotalProcessorTime;
            }
            catch (Exception e)
            {
                loggerInCtor.Error()?.LogException(e, "Failed reading Process Total CPU Time");
            }
        }
Пример #27
0
        /// <summary>
        /// Extracts the soap action from the header if exists only with Soap 1.1
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="logger">The logger.</param>
        public static string ExtractSoapAction(this HttpRequest request, IApmLogger logger)
        {
            try
            {
                return
                    (GetSoap11Action(request)
                     ?? GetSoap12Action(request));
            }
            catch (Exception e)
            {
                logger.Error()?.LogException(e, "Error reading soap action header");
            }

            return(null);
        }
Пример #28
0
 internal IActionResult BuildResponse(HttpRequest httpRequest, HttpResponse httpResponse)
 {
     lock (_lock)
     {
         try
         {
             return(BuildResponseImpl(httpRequest, httpResponse));
         }
         catch (Exception ex)
         {
             _logger.Error()?.LogException(ex, nameof(BuildResponseImpl) + " thrown exception");
             _appliedByAgent.SetException(ex);
             throw;
         }
     }
 }
Пример #29
0
        private static void DoLog(this IApmLogger logger, LogLevel level, string message, Exception e, params object[] args)
        {
            try
            {
                var formatter = logger is ScopedLogger sl
                                        ? sl.GetOrAddFormatter(message, args)
                                        : Formatters.GetOrAdd(message, s => new LogValuesFormatter(s, args));

                var logValues = formatter.GetState(args);

                logger?.Log(level, logValues, e, (s, _) => formatter.Format(args));
            }
            catch (Exception exception)
            {
                logger?.Error()?.LogException(exception, "Exception during logging - some log lines can be missing");
            }
        }
Пример #30
0
 private static void FillSampledTransactionContextResponse(HttpContext context, Transaction transaction, IApmLogger logger)
 {
     try
     {
         transaction.Context.Response = new Response
         {
             Finished   = context.Response.HasStarted,                   //TODO ?
             StatusCode = context.Response.StatusCode,
             Headers    = GetHeaders(context.Response.Headers, transaction.ConfigSnapshot)
         };
     }
     catch (Exception ex)
     {
         // context.response is optional: https://github.com/elastic/apm-server/blob/64a4ab96ba138050fe496b17d31deb2cf8830deb/docs/spec/context.json#L16
         logger?.Error()
         ?.LogException(ex, "Exception thrown while trying to fill response context for sampled transaction {TransactionId}",
                        transaction.Id);
     }
 }