private static JsonTimelineMessage CreateJsonTimelineMessage(JsonAction action, string type)
        {
            JsonTimelineMessage timelineMessage = new JsonTimelineMessage();
            string eventName = action.ToString("G");

            if (type != null)
            {
                eventName += " - " + RemoveAssemblyDetails(type);
            }
            timelineMessage.AsTimelineMessage(eventName, new TimelineCategoryItem(action.ToString("G"), "#B3DF00", "#9BBB59"));
            return(timelineMessage);
        }
        public void Trace(TraceLevel level, string message, Exception ex)
        {
            // write to any existing trace writer
            if (_innerTraceWriter != null && level <= _innerTraceWriter.LevelFilter)
            {
                _innerTraceWriter.Trace(level, message, ex);
            }

            IExecutionTimer timer = _timerStrategy();

            if (_traceMessages.Count > 0)
            {
                // check message to see if serialization is complete
                if (message.StartsWith("Serialized JSON:", StringComparison.Ordinal) || message.StartsWith("Deserialized JSON:", StringComparison.Ordinal))
                {
                    TimerResult timeResult = null;
                    if (timer != null)
                    {
                        timeResult = timer.Stop(_start);
                        _timelineMessage.AsTimedMessage(timeResult);
                    }

                    // set final JSON onto previous message
                    JsonTraceMessage lastMessage = _traceMessages.Last();
                    lastMessage.JsonText = message.Substring(message.IndexOf(Environment.NewLine, StringComparison.Ordinal)).Trim();
                    lastMessage.Duration = (timeResult != null) ? (TimeSpan?)timeResult.Duration : null;

                    _traceMessages.Clear();
                    return;
                }
            }

            JsonAction action = JsonAction.Unknown;
            string     type   = null;
            string     json   = null;

            if (_traceMessages.Count == 0)
            {
                Match match = Regex.Match(message, @"^Started serializing ([^\s]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
                if (match.Success)
                {
                    type   = match.Groups[1].Value.TrimEnd('.');
                    action = JsonAction.Serialize;
                }
                else
                {
                    match = Regex.Match(message, @"^Started deserializing ([^\s]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
                    if (match.Success)
                    {
                        type   = match.Groups[1].Value.TrimEnd('.');
                        action = JsonAction.Deserialize;
                    }
                    else
                    {
                        if (message.StartsWith("Serialized JSON:", StringComparison.Ordinal))
                        {
                            action = JsonAction.Serialize;
                        }
                        else if (message.StartsWith("Deserialized JSON:", StringComparison.Ordinal))
                        {
                            action = JsonAction.Deserialize;
                        }

                        if (action != JsonAction.Unknown)
                        {
                            json    = message.Substring(message.IndexOf(Environment.NewLine, StringComparison.Ordinal)).Trim();
                            message = null;
                        }
                    }
                }

                // create timeline message
                // will be updated each trace with new duration
                _timelineMessage = CreateJsonTimelineMessage(action, type);
                _messageBroker.Publish(_timelineMessage);

                if (timer != null)
                {
                    _start = timer.Start();
                }
            }
            else
            {
                JsonTraceMessage previous = _traceMessages.Last();
                previous.Duration = null;

                action = previous.Action;
                type   = previous.Type;
            }

            TimerResult result = null;

            if (timer != null)
            {
                result = timer.Stop(_start);
                _timelineMessage.AsTimedMessage(result);
            }

            JsonTraceMessage traceMessage = new JsonTraceMessage
            {
                Ordinal     = _traceMessages.Count,
                MessageDate = DateTime.Now,
                Level       = level,
                Message     = message,
                Exception   = ex,
                JsonText    = json,
                Action      = action,
                Type        = (type != null) ? RemoveAssemblyDetails(type) : null,
                Duration    = (result != null) ? (TimeSpan?)result.Duration : null
            };

            _messageBroker.Publish(traceMessage);
            _traceMessages.Add(traceMessage);
        }