Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
Add default exception message to TraceEvent & Update README.md (#19)
Browse files Browse the repository at this point in the history
Added default exception message to TraceEvent when format input is empty to use default message.

* Update README.md
* Modify format check and stacktrace variables
* Storing GetMethod in a variable to access once.
* Added IsNullOrEmpty check on format.
* Moved code to two functions for better resuability. Added execution to MessageFromTraceEvent and MessageFromString so they're used through other TraceEvent/TraceData.
* Added Unit Tests

fixes #17
  • Loading branch information
joshd-7 authored and sirkirby committed Jul 25, 2016
1 parent 5e065d7 commit bd9a5c7
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 43 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -151,7 +151,7 @@ Raygun.Diagnostics.Settings.Client.AddWrapperExceptions(new List<Type> { typeof(
#endif

// add default tags to every message generated by app domain
Raygun.Diagnostics.Settings.DefaultTags.AddRange(new[] {"debug", "someDynamicString"});
Raygun.Diagnostics.Settings.DefaultTags = new[] {"debug", "someDynamicString"};
```
## Build ##
Using msbuild (v14+) against [Raygun.Diagnostics.csproj](src/Raygun.Diagnostics/Raygun.Diagnostics.csproj).
Expand Down
Expand Up @@ -184,6 +184,22 @@ public void RaygunStringTraceWithGroupKeyFiresEvent()
_listener.WriteMessage(context);

Assert.That(raygunCustomGrouping == groupKey, Is.True);
}
}

[Test]
public void RaygunEventTraceUseDefaultMessageFormatWithNullInput()
{
var context = _listener.MessageFromTraceEvent(new TraceEventCache(), "RaygunEventTraceUseDefaultMessageFormatWithNullInput", TraceEventType.Error, 1, null, _userInfo);

Assert.That(context.Exception.Message == "An unexpected error occurred while calling RaygunEventTraceUseDefaultMessageFormatWithNullInput in TraceListenerFromTraceEventFixture at line 192.", Is.True);
}

[Test]
public void RaygunEventTraceUseDefaultMessageFormatWithEmptyStringInput()
{
var context = _listener.MessageFromTraceEvent(new TraceEventCache(), "RaygunEventTraceUseDefaultMessageFormatWithEmptyStringInput", TraceEventType.Error, 1, string.Empty, _userInfo);

Assert.That(context.Exception.Message == "An unexpected error occurred while calling RaygunEventTraceUseDefaultMessageFormatWithEmptyStringInput in TraceListenerFromTraceEventFixture at line 200.", Is.True);
}
}
}
6 changes: 3 additions & 3 deletions src/Raygun.Diagnostics/Properties/AssemblyInfo.cs
Expand Up @@ -32,6 +32,6 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
129 changes: 91 additions & 38 deletions src/Raygun.Diagnostics/RaygunTraceListener.cs
Expand Up @@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
Expand All @@ -13,6 +14,7 @@
namespace Raygun.Diagnostics
{
public delegate void Grouped(object sender, RaygunCustomGroupingKeyEventArgs e, IMessageGroup group);

public class RaygunTraceListener : TraceListener
{

Expand All @@ -25,7 +27,7 @@ private static bool NotAlone()
{
// see if others are listening
return (Trace.Listeners != null && Trace.Listeners["RaygunTraceListener"] != null && Trace.Listeners.Count > 1);
}
}

/// <summary>
/// Emits an error message to Raygun.
Expand Down Expand Up @@ -58,9 +60,10 @@ public override void Fail(string message, string detailMessage)
/// <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode" />
/// </PermissionSet>
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id,
object data)
{
TraceData(eventCache, source, eventType, id, new[] { data });
TraceData(eventCache, source, eventType, id, new[] {data});
}

/// <summary>
Expand All @@ -75,7 +78,8 @@ public override void TraceData(TraceEventCache eventCache, string source, TraceE
/// <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode" />
/// </PermissionSet>
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data)
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id,
params object[] data)
{
if ((Filter != null) && !Filter.ShouldTrace(eventCache, source, eventType, id, null, null, null, data)) return;
var message = string.Format("{0} trace event", eventType);
Expand Down Expand Up @@ -111,7 +115,8 @@ public override void TraceEvent(TraceEventCache eventCache, string source, Trace
/// <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode" />
/// </PermissionSet>
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id,
string message)
{
if ((Filter != null) && !Filter.ShouldTrace(eventCache, source, eventType, id, message, null, null, null)) return;
WriteMessage(MessageFromTraceEvent(eventCache, source, eventType, id, message, null));
Expand All @@ -130,14 +135,17 @@ public override void TraceEvent(TraceEventCache eventCache, string source, Trace
/// <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode" />
/// </PermissionSet>
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id,
string format, params object[] args)
{
if ((Filter != null) && !Filter.ShouldTrace(eventCache, source, eventType, id, format, args, null, null)) return;
// look at the format and decide how to handle the message
// allows for an easy work around for using the Tace.TraceError method for passing custom argument data
WriteMessage(Regex.IsMatch(format, @"\{[0-9]+\}")
? MessageFromTraceEvent(eventCache, source, eventType, id, String.Format(format, args), null) // just formatted text
: MessageFromTraceEvent(eventCache, source, eventType, id, format, args)); // treat args as additional custom information
? MessageFromTraceEvent(eventCache, source, eventType, id, String.Format(format, args), null)
// just formatted text
: MessageFromTraceEvent(eventCache, source, eventType, id, format, args));
// treat args as additional custom information
}

/// <summary>
Expand Down Expand Up @@ -174,9 +182,9 @@ public virtual void WriteMessage(MessageContext message)
//Set the event handler to automatically handle custom grouping
if (message.Group != null)
{
Settings.Client.CustomGroupingKey += (sender, e) => { HandleGrouping(sender, e, message.Group); };
Settings.Client.CustomGroupingKey += (sender, e) => { HandleGrouping(sender, e, message.Group); };
}

Settings.Client.Send(message.Exception, message.Tags, message.Data, message.GetRaygunUser());
}
catch (Exception e)
Expand All @@ -185,7 +193,7 @@ public virtual void WriteMessage(MessageContext message)
Trace.TraceError("Error on Raygun Send() : {0}", e.Message);
}
}

/// <summary>
/// Method used to bind to the CustomGroupingKey event of the RaygunClient object
/// </summary>
Expand All @@ -194,13 +202,13 @@ public virtual void WriteMessage(MessageContext message)
/// <param name="group">The message group that contains the data to tell the Raygun client how to group the message</param>
private void HandleGrouping(object sender, RaygunCustomGroupingKeyEventArgs e, IMessageGroup group)
{
//Only override the grouping if specified
if (!String.IsNullOrEmpty(group.GroupKey))
{
e.CustomGroupingKey = group.GroupKey;
}
//Only override the grouping if specified
if (!String.IsNullOrEmpty(group.GroupKey))
{
e.CustomGroupingKey = group.GroupKey;
}

OnGrouping?.Invoke(sender, e, group);
OnGrouping?.Invoke(sender, e, group);
}

/// <summary>
Expand All @@ -210,13 +218,17 @@ private void HandleGrouping(object sender, RaygunCustomGroupingKeyEventArgs e, I
/// <param name="detail">The detail.</param>
/// <param name="eventType">Type of the event.</param>
/// <returns>MessageContext.</returns>
public virtual MessageContext MessageFromString(string message, string detail = null, TraceEventType eventType = TraceEventType.Information)
public virtual MessageContext MessageFromString(string message, string detail = null,
TraceEventType eventType = TraceEventType.Information)
{
try
{
if (!eventType.IsValid())
return null;

//Create default message
if (string.IsNullOrEmpty(message)) message = DefaultMessage();

var tags = new List<string>();
// get tags from the stack trace
tags.AddRange(GetAttributeTags());
Expand All @@ -243,14 +255,19 @@ public virtual MessageContext MessageFromString(string message, string detail =
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
/// <returns>MessageContext.</returns>
public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message, params object[] args)
public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache, string source,
TraceEventType eventType, int id, string message, params object[] args)
{
try
{
if (!eventType.IsValid())
return null;

var context = new MessageContext(new Exception(message), new List<string>(), new Dictionary<object, object>(), new UserInfo(AppDomain.CurrentDomain.FriendlyName) {IsAnonymous = true});
//Create default message
if (string.IsNullOrEmpty(message)) message = DefaultMessage();

var context = new MessageContext(new Exception(message), new List<string>(), new Dictionary<object, object>(),
new UserInfo(AppDomain.CurrentDomain.FriendlyName) {IsAnonymous = true});

// get tags from the stack trace
context.Tags.AddRange(GetAttributeTags());
Expand All @@ -266,15 +283,15 @@ public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache,
var custom = localArgs.FirstOrDefault(a => a is IDictionary);
if (custom != null)
{
context.Data = (IDictionary)custom;
context.Data = (IDictionary) custom;
localArgs.Remove(custom);
}

// check the args for tags
var tags = localArgs.FirstOrDefault(a => a is IList<string>);
if (tags != null)
{
context.Tags.AddRange((IList<string>)tags);
context.Tags.AddRange((IList<string>) tags);
localArgs.Remove(tags);
}

Expand All @@ -283,7 +300,7 @@ public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache,
if (error != null)
{
// use the arg exception for raygun and pass the message as custom data
context.Exception = (Exception)error;
context.Exception = (Exception) error;
context.Data.Add("Message", message);
localArgs.Remove(error);
}
Expand All @@ -310,7 +327,13 @@ public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache,
object userIsAnonymous;
user.TryGetPropertyValue("isAnonymous", out userIsAnonymous);

context.User = new UserInfo(username?.ToString()) { Id = userId?.ToString(), Email = userEmail?.ToString(), FullName = userFullName?.ToString(), FirstName = userFirstName?.ToString()};
context.User = new UserInfo(username?.ToString())
{
Id = userId?.ToString(),
Email = userEmail?.ToString(),
FullName = userFullName?.ToString(),
FirstName = userFirstName?.ToString()
};
}
else
{
Expand All @@ -324,8 +347,8 @@ public virtual MessageContext MessageFromTraceEvent(TraceEventCache eventCache,
var grouping = localArgs.FirstOrDefault(a => a.HasProperty("groupkey"));
if (grouping != null)
{
context.Group = GetGrouping(grouping);
localArgs.Remove(grouping);
context.Group = GetGrouping(grouping);
localArgs.Remove(grouping);
}

// add the rest
Expand Down Expand Up @@ -355,7 +378,9 @@ public static IUserInfo GetAttributeUser()
var stackFrames = st.GetFrames();
if (stackFrames == null) return null;

foreach (var method in (from frame in stackFrames where frame != null select frame.GetMethod() into method select method))
foreach (
var method in (from frame in stackFrames where frame != null select frame.GetMethod() into method select method)
)
{
var m = method;
#if NET46
Expand All @@ -371,22 +396,22 @@ public static IUserInfo GetAttributeUser()
return ((RaygunDiagnosticsUserAttribute) methodAttr).User;
if (classAttr != null)
return ((RaygunDiagnosticsUserAttribute) classAttr).User;

}
return null;
}

public static IMessageGroup GetGrouping(object group)
{
object groupKey = new object();
var grouping = new MessageGroup();
object groupKey = new object();
var grouping = new MessageGroup();

if (group.TryGetPropertyValue("groupkey", out groupKey))
{
grouping.GroupKey = groupKey.ToString();
}
if (group.TryGetPropertyValue("groupkey", out groupKey))
{
grouping.GroupKey = groupKey.ToString();
}

return grouping;
return grouping;
}

/// <summary>
Expand All @@ -400,12 +425,14 @@ public static IEnumerable<string> GetAttributeTags()
var stackFrames = st.GetFrames();
if (stackFrames == null) yield break;

foreach (var method in (from frame in stackFrames where frame != null select frame.GetMethod() into method select method))
foreach (
var method in (from frame in stackFrames where frame != null select frame.GetMethod() into method select method)
)
{
var m = method;
#if NET46
var classAttr = m.ReflectedType?.GetCustomAttribute(typeof (RaygunDiagnosticsAttribute));
var methodAttr = m.GetCustomAttribute(typeof (RaygunDiagnosticsAttribute));
var classAttr = m.ReflectedType?.GetCustomAttribute(typeof(RaygunDiagnosticsAttribute));
var methodAttr = m.GetCustomAttribute(typeof(RaygunDiagnosticsAttribute));
#else
var classAttr = m.ReflectedType != null ? m.ReflectedType.GetCustomAttributes(typeof(RaygunDiagnosticsAttribute), false).FirstOrDefault() : null;
var methodAttr = m.GetCustomAttributes(typeof(RaygunDiagnosticsAttribute), false).FirstOrDefault();
Expand All @@ -420,5 +447,31 @@ public static IEnumerable<string> GetAttributeTags()
yield return tag;
}
}

public static IDictionary<string, string> GetStackTraceDefaultMessageInfo()
{
var stackInfo = new Dictionary<string, string>();
var st = new StackTrace(true);
var stackFrames = st.GetFrames();
if (stackFrames == null) return new Dictionary<string, string>();

var stack = stackFrames.ToList().FirstOrDefault(f => !f.GetMethod().ReflectedType.Module.Name.Contains("Raygun.Diagnostics.dll")
&& !f.GetMethod().ReflectedType.Module.Name.Contains("System"));
var method = stack.GetMethod();

stackInfo.Add("MethodName", method.Name);
stackInfo.Add("ClassName", method.ReflectedType?.Name);
stackInfo.Add("LineNumber", stack.GetFileLineNumber().ToString());

return stackInfo;
}

private static string DefaultMessage()
{
//Retrieve stack trace info for default message
var stackInfo = GetStackTraceDefaultMessageInfo();
return $"An unexpected error occurred while calling {stackInfo["MethodName"]} in {stackInfo["ClassName"]} at line {stackInfo["LineNumber"]}.";
}

}
}

0 comments on commit bd9a5c7

Please sign in to comment.