private void AddAdditionalField(JsonTextWriter writer, KeyValuePair <object, object> property)
        {
            var key = property.Key as string;

            if (key == null)
            {
                return;
            }

            //According to the GELF spec, libraries should NOT allow to send id as additional field (_id)
            //Server MUST skip the field because it could override the MongoDB _key field
            if (key.Equals("id", StringComparison.OrdinalIgnoreCase))
            {
                key = "id_";
            }

            //According to the GELF spec, additional field keys should start with '_' to avoid collision
            if (!key.StartsWith("_", StringComparison.OrdinalIgnoreCase))
            {
                key = "_" + key;
            }

            var value = property.Value != null?property.Value.ToString() : null;

            if (!string.IsNullOrEmpty(value))
            {
                writer.Member(key).String(property.Value.ToString());
            }
        }
            public override IEnumerable <string> Entries(IList <ErrorLogEntry> entries, int index, int count, int total)
            {
                Debug.Assert(entries != null);
                Debug.Assert(index >= 0);
                Debug.Assert(index + count <= entries.Count);

                var writer = new StringWriter {
                    NewLine = "\n"
                };

                if (_wrapped)
                {
                    writer.WriteLine("<script type='text/javascript' language='javascript'>");
                    writer.WriteLine("//<[!CDATA[");
                }

                writer.Write(_callback);
                writer.Write('(');

                var json = new JsonTextWriter(writer);

                json.Object()
                .Member("total").Number(total)
                .Member("errors").Array();

                var requestUrl = $"{Context.Request.Scheme}://{Context.Request.Host}{Context.Request.Path}";

                for (var i = index; i < count; i++)
                {
                    var entry = entries[i];
                    writer.WriteLine();
                    if (i == 0)
                    {
                        writer.Write(' ');
                    }
                    writer.Write("  ");

                    var urlTemplate = $"{requestUrl}?id=" + Uri.EscapeDataString(entry.Id);

                    json.Object();
                    ErrorJson.EncodeMembers(entry.Error, json);
                    json.Member("hrefs")
                    .Array()
                    .Object()
                    .Member("type").String("text/html")
                    .Member("href").String(string.Format(urlTemplate, "detail")).Pop()
                    .Object()
                    .Member("type").String("application/json")
                    .Member("href").String(string.Format(urlTemplate, "json")).Pop()
                    .Object()
                    .Member("type").String("application/xml")
                    .Member("href").String(string.Format(urlTemplate, "xml")).Pop()
                    .Pop()
                    .Pop();
                }

                json.Pop();
                json.Pop();

                if (count > 0)
                {
                    writer.WriteLine();
                }

                writer.WriteLine(");");

                if (_wrapped)
                {
                    writer.WriteLine("//]]>");
                    writer.WriteLine("</script>");

                    if (count == 0)
                    {
                        writer.WriteLine(@"</body></html>");
                    }
                }

                yield return(writer.ToString());
            }
        public string GetGelfJson(Error error, string facility, ICollection <string> ignoredProperties = null)
        {
            if (error == null)
            {
                return(null);
            }

            StackFrame stackFrame = null;

            //If we are dealing with an exception, pass exception properties
            if (error.Exception != null)
            {
                stackFrame = new StackTrace(error.Exception, true).GetFrame(0);
            }

            //Figure out the short message
            var shortMessage = error.Message;

            if (shortMessage.Length > ShortMessageMaxLength)
            {
                shortMessage = shortMessage.Substring(0, ShortMessageMaxLength);
            }

            var            stringWriter = new StringWriter();
            JsonTextWriter writer       = new JsonTextWriter(stringWriter);

            writer.Object();

            //Construct the instance of GelfMessage
            //See https://github.com/Graylog2/graylog2-docs/wiki/GELF "Specification (version 1.0)"
            //Standard specification field
            writer.Member("version").String(GelfVersion);
            writer.Member("host").String(Dns.GetHostName());
            writer.Member("short_message").String(shortMessage);
            writer.Member("full_message").String(error.Message);
            writer.Member("timestamp").String(error.Time);
            writer.Member("level").String(3.ToString());
            writer.Member("facility").String((string.IsNullOrEmpty(facility) ? "GELF" : facility));
            writer.Member("line").String((stackFrame != null) ? stackFrame.GetFileLineNumber().ToString(CultureInfo.InvariantCulture) : string.Empty);
            writer.Member("file").String((stackFrame != null) ? stackFrame.GetFileName() : string.Empty);

            var properties = new Dictionary <object, object>();

            //Filling elmah properties

            string exceptionDetail;
            string stackDetail;

            GetExceptionMessages(error.Exception, out exceptionDetail, out stackDetail);
            properties.Add("ExceptionSource", error.Exception.Source);
            properties.Add("ExceptionMessage", exceptionDetail);
            properties.Add("StackTrace", stackDetail);


            properties.Add("application", error.ApplicationName);
            properties.Add("host", error.HostName);
            properties.Add("type", error.Type);
            properties.Add("message", error.Message);
            properties.Add("source", error.Source);
            properties.Add("detail", error.Detail);
            properties.Add("user", error.User);
            properties.Add("time", error.Time);
            properties.Add("statusCode", error.StatusCode);
            properties.Add("webHostHtmlMessage", error.WebHostHtmlMessage);

            properties.Add("queryString", error.QueryString.ToString("&", (k, v) => string.Format("{0}={1}", k, v)));
            properties.Add("form", error.Form.ToString(Environment.NewLine, (k, v) => string.Format("{0}={1}", k, v)));
            properties.Add("cookies", error.Cookies.ToString(Environment.NewLine, (k, v) => string.Format("{0}={1}", k, v)));

            foreach (var v in error.ServerVariables.ToDictionary())
            {
                properties.Add(v.Key, v.Value);
            }



            //Property filtering if is necessary
            if (ignoredProperties != null && ignoredProperties.Any())
            {
                properties = properties.Where(p => !ignoredProperties.Contains(p.Key.ToString())).ToDictionary(k => k.Key, v => v.Value);
            }

            //Convert to JSON
            //We will persist them "Additional Fields" according to Gelf spec
            foreach (var p in properties)
            {
                AddAdditionalField(writer, p);
            }

            writer.Pop();

            return(stringWriter.ToString());
        }