/// <summary>
    /// Generates a message context from a trace event.
    /// </summary>
    /// <param name="eventCache">The event cache.</param>
    /// <param name="source">The source.</param>
    /// <param name="eventType">Type of the event.</param>
    /// <param name="id">The identifier.</param>
    /// <param name="message">The message.</param>
    /// <param name="args">The arguments.</param>
    /// <returns>MessageContext.</returns>
    protected 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>());

        // get tags from the stack trace
        context.Tags.AddRange(GetAttributeTags());

        if (args != null)
        {
          var localArgs = args.Where(a => a != null).ToList();
          // check the args for custom data
          var custom = localArgs.FirstOrDefault(a => a is IDictionary);
          if (custom != null)
          {
            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);
            localArgs.Remove(tags);
          }

          // check the args for a custom exception
          var error = localArgs.FirstOrDefault(a => a is Exception);
          if (error != null)
          {
            // use the arg exception for raygun and pass the message as custom data
            context.Exception = (Exception)error;
            context.Data.Add("Message", message);
            localArgs.Remove(error);
          }
          else
          {
            // wrap the trace message as the exception
            context.Exception = new Exception(message);
          }

          // add the rest
          var count = 0;
          foreach (var leftover in localArgs)
            context.Data.Add(String.Format("arg-{0}", count++), leftover);
        }

        return context;
      }
      catch (Exception e)
      {
        if (NotAlone()) // if someone else is listening, then trace the error
          Trace.TraceError("Error on MessageFromTraceEvent in RaygunTraceListener : {0}", e.Message);
        return new MessageContext(e);
      }
    }
    /// <summary>
    /// Sends the message to Raygun
    /// </summary>
    /// <param name="message">The message.</param>
    protected virtual void WriteMessage(MessageContext message)
    {
      if (message == null || Settings.Debug) return;
      try
      {
        // add default tags to every send if specified
        if (Settings.DefaultTags != null)
          message.Tags.AddRange(Settings.DefaultTags);

        Settings.Client.Send(message.Exception, message.Tags, message.Data);
      }
      catch (Exception e)
      {
        if (NotAlone()) // if someone else is listening, then trace the error
          Trace.TraceError("Error on Raygun Send() : {0}", e.Message);
      }
    }