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