示例#1
0
 public SentryTracingMiddleware(
     RequestDelegate next,
     Func <IHub> getHub,
     IOptions <SentryAspNetCoreOptions> options)
 {
     _next    = next;
     _getHub  = getHub;
     _options = options.Value;
 }
示例#2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SentryMiddleware"/> class.
 /// </summary>
 /// <param name="next">The next.</param>
 /// <param name="getHub">The sentry Hub accessor.</param>
 /// <param name="options">The options for this integration</param>
 /// <param name="hostingEnvironment">The hosting environment.</param>
 /// <param name="logger">Sentry logger.</param>
 /// <exception cref="ArgumentNullException">
 /// next
 /// or
 /// sentry
 /// </exception>
 public SentryMiddleware(
     RequestDelegate next,
     Func <IHub> getHub,
     IOptions <SentryAspNetCoreOptions> options,
     IHostingEnvironment hostingEnvironment,
     ILogger <SentryMiddleware> logger)
 {
     _next               = next ?? throw new ArgumentNullException(nameof(next));
     _getHub             = getHub ?? throw new ArgumentNullException(nameof(getHub));
     _options            = options.Value;
     _hostingEnvironment = hostingEnvironment;
     _logger             = logger;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SentryMiddleware"/> class.
 /// </summary>
 /// <param name="next">The next.</param>
 /// <param name="sentry">The sentry.</param>
 /// <param name="options">The options for this integration</param>
 /// <param name="hostingEnvironment">The hosting environment.</param>
 /// <param name="logger">Sentry logger.</param>
 /// <exception cref="ArgumentNullException">
 /// next
 /// or
 /// sentry
 /// </exception>
 public SentryMiddleware(
     RequestDelegate next,
     IHub sentry,
     SentryAspNetCoreOptions options,
     IHostingEnvironment hostingEnvironment,
     ILogger <SentryMiddleware> logger)
 {
     _next               = next ?? throw new ArgumentNullException(nameof(next));
     _sentry             = sentry ?? throw new ArgumentNullException(nameof(sentry));
     _options            = options;
     _hostingEnvironment = hostingEnvironment;
     _logger             = logger;
 }
        private static void SetBody(Scope scope, HttpContext context, SentryAspNetCoreOptions options)
        {
            var extractors = context.RequestServices.GetService <IEnumerable <IRequestPayloadExtractor> >();

            if (extractors == null)
            {
                return;
            }
            var dispatcher = new RequestBodyExtractionDispatcher(extractors, options, () => options.MaxRequestBodySize);

            var body = dispatcher.ExtractPayload(new HttpRequestAdapter(context.Request));

            if (body != null)
            {
                scope.Request.Data = body;
            }
        }
        private static void SetEnv(Scope scope, HttpContext context, SentryAspNetCoreOptions options)
        {
            scope.Request.Method = context.Request.Method;

            // Logging integration, if enabled, sets the following tag which ends up as duplicate
            // to Request.Url. Prefer the interface value and remove tag.
            var host = context.Request.Host.Host;

            if (context.Request.Host.Port != null)
            {
                host += $":{context.Request.Host.Port}";
            }
            scope.Request.Url = $"{context.Request.Scheme}://{host}{context.Request.Path}";
            scope.UnsetTag("RequestPath");

            scope.Request.QueryString = context.Request.QueryString.ToString();
            foreach (var requestHeader in context.Request.Headers)
            {
                if (options?.SendDefaultPii != true
                    // Don't add headers which might contain PII
                    && (requestHeader.Key == HeaderNames.Cookie ||
                        requestHeader.Key == HeaderNames.Authorization))
                {
                    continue;
                }

                scope.Request.Headers[requestHeader.Key] = requestHeader.Value;
            }

            // TODO: Hide these 'Env' behind some extension method as
            // these might be reported in a non CGI, old-school way
            if (options?.SendDefaultPii == true &&
                context.Connection.RemoteIpAddress?.ToString() is { } ipAddress)
            {
                scope.Request.Env["REMOTE_ADDR"] = ipAddress;
            }

            scope.Request.Env["SERVER_NAME"] = Environment.MachineName;
            scope.Request.Env["SERVER_PORT"] = context.Connection.LocalPort.ToString();

            if (context.Response.Headers.TryGetValue("Server", out var server))
            {
                scope.Request.Env["SERVER_SOFTWARE"] = server;
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="SentryMiddleware"/> class.
        /// </summary>
        /// <param name="next">The next.</param>
        /// <param name="getHub">The sentry Hub accessor.</param>
        /// <param name="options">The options for this integration</param>
        /// <param name="hostingEnvironment">The hosting environment.</param>
        /// <param name="logger">Sentry logger.</param>
        /// <exception cref="ArgumentNullException">
        /// next
        /// or
        /// sentry
        /// </exception>
        public SentryMiddleware(
            RequestDelegate next,
            Func <IHub> getHub,
            IOptions <SentryAspNetCoreOptions> options,
            IHostingEnvironment hostingEnvironment,
            ILogger <SentryMiddleware> logger)
        {
            _next    = next ?? throw new ArgumentNullException(nameof(next));
            _getHub  = getHub ?? throw new ArgumentNullException(nameof(getHub));
            _options = options.Value;
            var hub = _getHub();

            foreach (var callback in _options.ConfigureScopeCallbacks)
            {
                hub.ConfigureScope(callback);
            }
            _hostingEnvironment = hostingEnvironment;
            _logger             = logger;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SentryMiddleware"/> class.
 /// </summary>
 /// <param name="next">The next.</param>
 /// <param name="hubAccessor">The sentry Hub accessor.</param>
 /// <param name="options">The options for this integration</param>
 /// <param name="hostingEnvironment">The hosting environment.</param>
 /// <param name="logger">Sentry logger.</param>
 /// <exception cref="ArgumentNullException">
 /// next
 /// or
 /// sentry
 /// </exception>
 public SentryMiddleware(
     RequestDelegate next,
     Func <IHub> hubAccessor,
     IOptions <SentryAspNetCoreOptions> options,
     IHostingEnvironment hostingEnvironment,
     ILogger <SentryMiddleware> logger)
 {
     _next        = next ?? throw new ArgumentNullException(nameof(next));
     _hubAccessor = hubAccessor ?? throw new ArgumentNullException(nameof(hubAccessor));
     _options     = options?.Value;
     if (_options != null)
     {
         var hub = _hubAccessor();
         foreach (var callback in _options.ConfigureScopeCallbacks)
         {
             hub.ConfigureScope(callback);
         }
     }
     _hostingEnvironment = hostingEnvironment;
     _logger             = logger;
 }
        /// <summary>
        /// Populates the scope with the HTTP data
        /// </summary>
        /// <remarks>
        /// NOTE: The scope is applied to the event BEFORE running the event processors/exception processors.
        /// The main Sentry SDK has processors which run right before any additional processors to the Event
        /// </remarks>
        public static void Populate(this Scope scope, HttpContext context, SentryAspNetCoreOptions options)
        {
            // With the logger integration, a BeginScope call is made with RequestId. That ends up adding
            // two tags with the same value: RequestId and TraceIdentifier
            if (!scope.Tags.TryGetValue("RequestId", out var requestId) || requestId != context.TraceIdentifier)
            {
                scope.SetTag(nameof(context.TraceIdentifier), context.TraceIdentifier);
            }

            if (options?.SendDefaultPii == true && !scope.HasUser())
            {
                var userFactory = context.RequestServices?.GetService <IUserFactory>();
                if (userFactory != null)
                {
                    scope.User = userFactory.Create(context);
                }
            }

            try
            {
                SetBody(scope, context, options);
            }
            catch (Exception e)
            {
                options?.DiagnosticLogger?.LogError("Failed to extract body.", e);
            }
            SetEnv(scope, context, options);

            // TODO: From MVC route template, ideally
            // TODO: optionally get transaction from request through a dependency
            //scope.Transation = context.Request.Path;

            // TODO: Get context stuff into scope
            //context.Session
            //context.Response
            //context.Items
        }
        /// <summary>
        /// Populates the scope with the HTTP data
        /// </summary>
        /// <remarks>
        /// NOTE: The scope is applied to the event BEFORE running the event processors/exception processors.
        /// The main Sentry SDK has processors which run right before any additional processors to the Event
        /// </remarks>
        public static void Populate(this Scope scope, HttpContext context, SentryAspNetCoreOptions options)
        {
            // With the logger integration, a BeginScope call is made with RequestId. That ends up adding
            // two tags with the same value: RequestId and TraceIdentifier
            if (!scope.Tags.TryGetValue("RequestId", out var requestId) || requestId != context.TraceIdentifier)
            {
                scope.SetTag(nameof(context.TraceIdentifier), context.TraceIdentifier);
            }

            if (options?.SendDefaultPii == true && !scope.HasUser())
            {
                var userFactory = context.RequestServices?.GetService <IUserFactory>();
                if (userFactory != null)
                {
                    scope.User = userFactory.Create(context);
                }
            }

            try
            {
                SetBody(scope, context, options);
            }
            catch (Exception e)
            {
                options?.DiagnosticLogger?.LogError("Failed to extract body.", e);
            }
            SetEnv(scope, context, options);

            // Extract the route data
            try
            {
                var routeData = context.GetRouteData();
                if (routeData != null)
                {
                    var controller = routeData.Values["controller"]?.ToString();
                    var action     = routeData.Values["action"]?.ToString();
                    var area       = routeData.Values["area"]?.ToString();

                    if (controller != null)
                    {
                        scope.SetTag("route.controller", controller);
                    }
                    if (action != null)
                    {
                        scope.SetTag("route.action", action);
                    }
                    if (area != null)
                    {
                        scope.SetTag("route.area", area);
                    }

                    scope.Transaction = area == null ? $"{controller}.{action}" : $"{area}.{controller}.{action}";
                }
            }
            catch (Exception e)
            {
                // Suppress the error here; we expect an ArgumentNullException if httpContext.Request.RouteValues is null from GetRouteData()
                // TODO: Consider adding a bool to the Sentry options to make route data extraction optional in case they don't use a routing middleware?
                options?.DiagnosticLogger?.LogDebug("Failed to extract route data.", e);
            }

            // TODO: Get context stuff into scope
            //context.Session
            //context.Response
            //context.Items
        }
示例#10
0
        /// <summary>
        /// Populates the scope with the HTTP data
        /// </summary>
        /// <remarks>
        /// NOTE: The scope is applied to the event BEFORE running the event processors/exception processors.
        /// The main Sentry SDK has processors which run right before any additional processors to the Event
        /// </remarks>
        public static void Populate(this Scope scope, HttpContext context, SentryAspNetCoreOptions options)
        {
            // Not to throw on code that ignores nullability warnings.
            // ReSharper disable ConditionIsAlwaysTrueOrFalse
            if (scope is null || context is null || options is null)
            {
                return;
            }
            // ReSharper restore ConditionIsAlwaysTrueOrFalse

            // With the logger integration, a BeginScope call is made with RequestId. That ends up adding
            // two tags with the same value: RequestId and TraceIdentifier
            if (!scope.Tags.TryGetValue("RequestId", out var requestId) || requestId != context.TraceIdentifier)
            {
                scope.SetTag(nameof(context.TraceIdentifier), context.TraceIdentifier);
            }

            if (options.SendDefaultPii && !scope.HasUser())
            {
                var userFactory = context.RequestServices.GetService <IUserFactory>();
                var user        = userFactory?.Create(context);

                if (user != null)
                {
                    scope.User = user;
                }
            }

            try
            {
                SetBody(scope, context, options);
            }
            catch (Exception e)
            {
                options.LogError("Failed to extract body.", e);
            }

            SetEnv(scope, context, options);

            // Extract the route data
            try
            {
                var routeData  = context.GetRouteData();
                var controller = routeData.Values["controller"]?.ToString();
                var action     = routeData.Values["action"]?.ToString();
                var area       = routeData.Values["area"]?.ToString();

                if (controller != null)
                {
                    scope.SetTag("route.controller", controller);
                }

                if (action != null)
                {
                    scope.SetTag("route.action", action);
                }

                if (area != null)
                {
                    scope.SetTag("route.area", area);
                }

                // Transaction Name may only be available afterward the creation of the Transaction.
                // In this case, the event will update the transaction name if captured during the
                // pipeline execution, allowing it to match the correct transaction name as the current
                // active transaction.
                if (string.IsNullOrEmpty(scope.TransactionName))
                {
                    scope.TransactionName = context.TryGetTransactionName();
                }
            }
            catch (Exception e)
            {
                // Suppress the error here; we expect an ArgumentNullException if httpContext.Request.RouteValues is null from GetRouteData()
                // TODO: Consider adding a bool to the Sentry options to make route data extraction optional in case they don't use a routing middleware?
                options.LogDebug("Failed to extract route data.", e);
            }

            // TODO: Get context stuff into scope
            //context.Session
            //context.Response
            //context.Items
        }