private void StopTimerAndReport(IInvocation invocation, Exception exception = null)
        {
            if (!StatsdClientWrapper.IsEnabled)
            {
                return;
            }

            var stopwatch = _stopWatchThreadLocal.Value[invocation.Method.MethodHandle];

            var elapsedMilliseconds = (int)stopwatch.ElapsedMilliseconds;

            stopwatch.Reset();

            var actionName = invocation.Method.Name.ToLower();

            var metricName = GetMetricName(invocation, actionName, exception);

            StatsdClientWrapper.Timer(metricName, elapsedMilliseconds);
            StatsdClientWrapper.Counter(metricName);
        }
        public void Dispose()
        {
            if (string.IsNullOrEmpty(ActionName))
            {
                return;
            }

            _stopwatch.Stop();

            //=======================================
            // .NET has a technique to detect whether an exception has been thrown from within a finally:
            // http://stackoverflow.com/questions/2830073/detecting-a-dispose-from-an-exception-inside-using-block
            // (Marshal.GetExceptionPointers() != IntPtr.Zero || Marshal.GetExceptionCode() != 0);
            // however, this is not yet implemented in Mono
            // http://www.go-mono.com/momareports/apis/System.Int32%20System.Runtime.InteropServices.Marshal;;GetExceptionCode%28%29
            // so: caller can manage this property manually in a try-catch nested witin the attribute, if desired
            //=======================================
            var metricName = CommonHelpers.MetricName(ExceptionThrown, ActionName);

            StatsdClientWrapper.Timer(metricName, (int)_stopwatch.ElapsedMilliseconds);
            StatsdClientWrapper.Counter(metricName);
        }
Exemple #3
0
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            try
            {
                if (!StatsdClientWrapper.IsEnabled)
                {
                    return;
                }

                var stopwatch = actionExecutedContext.Request.Properties[StopwatchKey] as Stopwatch;

                if (stopwatch == null)
                {
                    return;
                }

                var elapsedMilliseconds = (int)stopwatch.ElapsedMilliseconds;
                stopwatch.Reset();

                var actionName = string.IsNullOrEmpty(SuppliedActionName)
                                    ? actionExecutedContext.ActionContext.ActionDescriptor.ActionName
                                    : SuppliedActionName;

                var apiVersion = GetApiVersion(actionExecutedContext);

                var httpVerb = actionExecutedContext.Request.Method.ToString();

                int statusCode = 0;
                var otEndpoint = string.Format("{0}-{1}", actionName, apiVersion).ToLower();
                if (actionExecutedContext.Response != null)
                {
                    // controller returns HttpResponseMessage or threw a HttpResponseException

                    statusCode = (int)actionExecutedContext.Response.StatusCode;

                    // Look for endpoint name in the response headers, if one exists we will use it to
                    // publish metircs.  If not will default to action name and will set the header
                    // value as such for upstream services.
                    IEnumerable <string> headerValues;
                    if (actionExecutedContext.Response.Headers.TryGetValues(StatsdConstants.OtEndpoint, out headerValues))
                    {
                        otEndpoint = string.Format("{0}-{1}", headerValues.FirstOrDefault() ?? actionName, apiVersion).ToLower();
                    }
                    else
                    {
                        actionExecutedContext.Response.Headers.Add(StatsdConstants.OtEndpoint, otEndpoint);
                    }
                }
                else if (actionExecutedContext.Exception != null)
                {
                    // controllers threw exception that is not typeof(HttpResponseException)

                    if (CommonHelpers.ExceptionToStatusCode != null)
                    {
                        var statusCodeEnum = CommonHelpers.ExceptionToStatusCode(actionExecutedContext.Exception,
                                                                                 actionExecutedContext);
                        statusCode = (int)statusCodeEnum;
                        actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(statusCodeEnum);
                        actionExecutedContext.Response.Headers.Add(StatsdConstants.OtEndpoint, otEndpoint);
                    }
                }


                var status = CommonHelpers.GetHighlevelStatus(IsSuccessStatusCode(statusCode));
                // not being able to read status code will result in status code being set to undefined
                var statusCodeString = statusCode == 0
                    ? StatsdConstants.Undefined
                    : statusCode.ToString(CultureInfo.InvariantCulture);
                var metricName = string.Format(
                    "{0}.{1}.{2}.{3}.{4}.{5}",
                    StatsdConstants.HttpRequestIn,
                    GetReferringService(actionExecutedContext),
                    otEndpoint,
                    status,
                    httpVerb,
                    statusCodeString).Replace('_', '-').ToLower();

                StatsdClientWrapper.Timer(metricName, elapsedMilliseconds);
                StatsdClientWrapper.Counter(metricName);

                EnrichResponseHeaders(actionExecutedContext);
            }
            finally
            {
                base.OnActionExecuted(actionExecutedContext);
            }
        }