public void CreateTraceMonitor_AllErrors() { ParameterInfo parameter = typeof(Functions).GetMethod("AllErrors").GetParameters()[0]; TraceMonitor traceMonitor = ErrorTriggerListener.CreateTraceMonitor(parameter, _mockExecutor.Object); TraceFilter.AnonymousTraceFilter traceFilter = (TraceFilter.AnonymousTraceFilter)traceMonitor.Filters.Single(); Assert.Equal("One or more WebJob errors have occurred.", traceFilter.Message); int notification = 0; traceMonitor.Subscribe(p => notification++); Assert.Equal(0, traceFilter.GetEvents().Count()); traceMonitor.Trace(new TraceEvent(TraceLevel.Error, "Error1")); IEnumerable <TraceEvent> traceEvents = traceFilter.GetEvents(); Assert.Equal(1, traceEvents.Count()); Assert.Equal("Error1", traceEvents.Single().Message); traceMonitor.Trace(new TraceEvent(TraceLevel.Error, "Error2")); traceEvents = traceFilter.GetEvents(); Assert.Equal(1, traceEvents.Count()); Assert.Equal("Error2", traceEvents.Single().Message); Assert.Equal(2, notification); }
public void CreateTraceMonitor_AllErrors_Customized() { ParameterInfo parameter = typeof(Functions).GetMethod("AllErrors_Customized").GetParameters()[0]; TraceMonitor traceMonitor = ErrorTriggerListener.CreateTraceMonitor(parameter, _mockExecutor.Object); Assert.Equal(TimeSpan.Parse("00:30:00"), traceMonitor.NotificationThrottle); TraceFilter.AnonymousTraceFilter traceFilter = (TraceFilter.AnonymousTraceFilter)traceMonitor.Filters.Single(); Assert.Equal("Custom Message", traceFilter.Message); int notification = 0; traceMonitor.Subscribe(p => notification++); Assert.Equal(0, traceFilter.GetEvents().Count()); traceMonitor.Trace(new TraceEvent(TraceLevel.Error, "Error1")); Assert.Equal(1, traceFilter.GetEvents().Count()); Assert.Equal("Error1", traceFilter.GetEvents().Single().Message); traceMonitor.Trace(new TraceEvent(TraceLevel.Error, "Error2")); Assert.Equal(1, traceFilter.GetEvents().Count()); Assert.Equal("Error2", traceFilter.GetEvents().Single().Message); // expect second notification to be ignored due to throttle Assert.Equal(1, notification); }
internal static TraceMonitor CreateTraceMonitor(ParameterInfo parameter, ITriggeredFunctionExecutor executor) { ErrorTriggerAttribute attribute = parameter.GetCustomAttribute<ErrorTriggerAttribute>(inherit: false); // Determine whether this is a method level filter, and if so, create the filter Func<TraceEvent, bool> methodFilter = null; MethodInfo method = (MethodInfo)parameter.Member; string functionLevelMessage = null; if (method.Name.EndsWith(ErrorHandlerSuffix, StringComparison.OrdinalIgnoreCase)) { string sourceMethodName = method.Name.Substring(0, method.Name.Length - ErrorHandlerSuffix.Length); MethodInfo sourceMethod = method.DeclaringType.GetMethod(sourceMethodName); if (sourceMethod != null) { string sourceMethodFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, sourceMethod.Name); methodFilter = p => { FunctionInvocationException functionException = p.Exception as FunctionInvocationException; return p.Level == System.Diagnostics.TraceLevel.Error && functionException != null && string.Compare(functionException.MethodName, sourceMethodFullName, StringComparison.OrdinalIgnoreCase) == 0; }; string sourceMethodShortName = string.Format("{0}.{1}", method.DeclaringType.Name, sourceMethod.Name); functionLevelMessage = string.Format("Function '{0}' failed.", sourceMethodShortName); } } string errorHandlerFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name); ErrorHandlers.Add(errorHandlerFullName); // Create the TraceFilter instance TraceFilter traceFilter = null; if (attribute.FilterType != null) { if (methodFilter != null) { TraceFilter innerTraceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); traceFilter = new CompositeTraceFilter(innerTraceFilter, methodFilter, attribute.Message ?? functionLevelMessage); } else { traceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); } } else if (!string.IsNullOrEmpty(attribute.Window)) { TimeSpan window = TimeSpan.Parse(attribute.Window); traceFilter = new SlidingWindowTraceFilter(window, attribute.Threshold, methodFilter, attribute.Message); } else { traceFilter = TraceFilter.Create(methodFilter, attribute.Message ?? functionLevelMessage); } TraceMonitor traceMonitor = new TraceMonitor().Filter(traceFilter); // Apply any additional monitor options if (!string.IsNullOrEmpty(attribute.Throttle)) { TimeSpan throttle = TimeSpan.Parse(attribute.Throttle); traceMonitor.Throttle(throttle); } // Subscribe the error handler function to the error stream traceMonitor.Subscribe(p => { TriggeredFunctionData triggerData = new TriggeredFunctionData { TriggerValue = p }; Task<FunctionResult> task = executor.TryExecuteAsync(triggerData, CancellationToken.None); task.Wait(); }); return traceMonitor; }
internal static TraceMonitor CreateTraceMonitor(ParameterInfo parameter, ITriggeredFunctionExecutor executor) { ErrorTriggerAttribute attribute = parameter.GetCustomAttribute <ErrorTriggerAttribute>(inherit: false); // Determine whether this is a method level filter, and if so, create the filter Func <TraceEvent, bool> methodFilter = null; MethodInfo method = (MethodInfo)parameter.Member; string functionLevelMessage = null; if (method.Name.EndsWith(ErrorHandlerSuffix, StringComparison.OrdinalIgnoreCase)) { string sourceMethodName = method.Name.Substring(0, method.Name.Length - ErrorHandlerSuffix.Length); MethodInfo sourceMethod = method.DeclaringType.GetMethod(sourceMethodName); if (sourceMethod != null) { string sourceMethodFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, sourceMethod.Name); methodFilter = p => { FunctionInvocationException functionException = p.Exception as FunctionInvocationException; return(p.Level == System.Diagnostics.TraceLevel.Error && functionException != null && string.Compare(functionException.MethodName, sourceMethodFullName, StringComparison.OrdinalIgnoreCase) == 0); }; string sourceMethodShortName = string.Format("{0}.{1}", method.DeclaringType.Name, sourceMethod.Name); functionLevelMessage = string.Format("Function '{0}' failed.", sourceMethodShortName); } } string errorHandlerFullName = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name); ErrorHandlers.Add(errorHandlerFullName); // Create the TraceFilter instance TraceFilter traceFilter = null; if (attribute.FilterType != null) { if (methodFilter != null) { TraceFilter innerTraceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); traceFilter = new CompositeTraceFilter(innerTraceFilter, methodFilter, attribute.Message ?? functionLevelMessage); } else { traceFilter = (TraceFilter)Activator.CreateInstance(attribute.FilterType); } } else if (!string.IsNullOrEmpty(attribute.Window)) { TimeSpan window = TimeSpan.Parse(attribute.Window); traceFilter = new SlidingWindowTraceFilter(window, attribute.Threshold, methodFilter, attribute.Message); } else { traceFilter = TraceFilter.Create(methodFilter, attribute.Message ?? functionLevelMessage); } TraceMonitor traceMonitor = new TraceMonitor().Filter(traceFilter); // Apply any additional monitor options if (!string.IsNullOrEmpty(attribute.Throttle)) { TimeSpan throttle = TimeSpan.Parse(attribute.Throttle); traceMonitor.Throttle(throttle); } // Subscribe the error handler function to the error stream traceMonitor.Subscribe(p => { TriggeredFunctionData triggerData = new TriggeredFunctionData { TriggerValue = p }; Task <FunctionResult> task = executor.TryExecuteAsync(triggerData, CancellationToken.None); task.Wait(); }); return(traceMonitor); }