<commit_before>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Kudu.Contracts.Tracing;
using Kudu.Core.Infrastructure;

namespace Kudu.Core.Tracing
{
    // This writes traces for each request.  Each request will be traced in a different file.
    // The format is XML.  There is a MaxXmlFiles limit to keep the most recent traces.
    public class XmlTracer : ITracer
    {
        public const string IncomingRequestTrace = "Incoming Request";
        public const string OutgoingResponseTrace = "Outgoing response";
        public const string StartupRequestTrace = "Startup Request";
        public const string ProcessShutdownTrace = "Process Shutdown";
        public const string ExecutingExternalProcessTrace = "Executing external process";
        public const string BackgroundTrace = "BackgroundTrace";

        public const int MaxXmlFiles = 200;
        public const int CleanUpIntervalSecs = 10;

        private static object _cleanupLock = new object();
        private static bool _cleanupPending = false;
        private const string PendingXml = "_pending.xml";
        private static long _salt = 0;
        private static DateTime _lastCleanup = DateTime.MinValue;

        private readonly static TimeSpan ElapsedThreshold = TimeSpan.FromSeconds(10);
        private readonly static string[] TraceFilters = new[]
        {
            // portal polling
            "/api/webjobs",
            "/api/siteextensions",
            "/api/processes",
            "/api/deployments",
        };

        private Stack<TraceInfo> _infos;
        private string _path;
        private string _file;
        private int _statusCode;
        private bool _isStartElement;
        private TraceLevel _level;

        public XmlTracer(string path, TraceLevel level)
        {
            _path = path;
            _level = level;

            _infos = new Stack<TraceInfo>();
            _isStartElement = false;
        }

        public TraceLevel TraceLevel
        {
            get { return _level; }
        }

        public IDisposable Step(string title, IDictionary<string, string> attributes)
        {
            if (_level <= TraceLevel.Off)
            {
                return DisposableAction.Noop;
            }

            return WriteStartElement(title, attributes);
        }

        public void Trace(string value, IDictionary<string, string> attributes)
        {
            // Add a fake step
            using (Step(value, attributes)) { }
        }

        private IDisposable WriteStartElement(string title, IDictionary<string, string> attribs)
        {
            try
            {
                var info = new TraceInfo(title, attribs);

                var ensureMaxXmlFiles = false;
                if (String.IsNullOrEmpty(_file))
                {
                    ensureMaxXmlFiles = true;

                    // generate trace file name base on attribs
                    _file = GenerateFileName(info);
                }

                var strb = new StringBuilder();

                if (_isStartElement)
                {
                    strb.AppendLine(">");
                }

                strb.Append(new String(' ', _infos.Count * 2));
                strb.AppendFormat("<step title=\"{0}\" ", XmlUtility.EscapeXmlText(title));
                strb.AppendFormat("date=\"{0}\" ", info.StartTime.ToString("yyy-MM-ddTHH:mm:ss.fff"));
                if (_infos.Count == 0)
                {
                    strb.AppendFormat("instance=\"{0}\" ", InstanceIdUtility.GetShortInstanceId());
                }

                foreach (var attrib in attribs)
                {
                    if (TraceExtensions.IsNonDisplayableAttribute(attrib.Key))
                    {
                        continue;
                    }

                    strb.AppendFormat("{0}=\"{1}\" ", attrib.Key, XmlUtility.EscapeXmlText(attrib.Value));
                }

                FileSystemHelpers.AppendAllTextToFile(_file, strb.ToString());
                _infos.Push(info);
                _isStartElement = true;

                if (ensureMaxXmlFiles)
                {
                    EnsureMaxXmlFiles();
                }<commit_msg>fix trivial typo<commit_after>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Kudu.Contracts.Tracing;
using Kudu.Core.Infrastructure;

namespace Kudu.Core.Tracing
{
    // This writes traces for each request.  Each request will be traced in a different file.
    // The format is XML.  There is a MaxXmlFiles limit to keep the most recent traces.
    public class XmlTracer : ITracer
    {
        public const string IncomingRequestTrace = "Incoming Request";
        public const string OutgoingResponseTrace = "Outgoing response";
        public const string StartupRequestTrace = "Startup Request";
        public const string ProcessShutdownTrace = "Process Shutdown";
        public const string ExecutingExternalProcessTrace = "Executing external process";
        public const string BackgroundTrace = "BackgroundTrace";

        public const int MaxXmlFiles = 200;
        public const int CleanUpIntervalSecs = 10;

        private static object _cleanupLock = new object();
        private static bool _cleanupPending = false;
        private const string PendingXml = "_pending.xml";
        private static long _salt = 0;
        private static DateTime _lastCleanup = DateTime.MinValue;

        private readonly static TimeSpan ElapsedThreshold = TimeSpan.FromSeconds(10);
        private readonly static string[] TraceFilters = new[]
        {
            // portal polling
            "/api/webjobs",
            "/api/siteextensions",
            "/api/processes",
            "/api/deployments",
        };

        private Stack<TraceInfo> _infos;
        private string _path;
        private string _file;
        private int _statusCode;
        private bool _isStartElement;
        private TraceLevel _level;

        public XmlTracer(string path, TraceLevel level)
        {
            _path = path;
            _level = level;

            _infos = new Stack<TraceInfo>();
            _isStartElement = false;
        }

        public TraceLevel TraceLevel
        {
            get { return _level; }
        }

        public IDisposable Step(string title, IDictionary<string, string> attributes)
        {
            if (_level <= TraceLevel.Off)
            {
                return DisposableAction.Noop;
            }

            return WriteStartElement(title, attributes);
        }

        public void Trace(string value, IDictionary<string, string> attributes)
        {
            // Add a fake step
            using (Step(value, attributes)) { }
        }

        private IDisposable WriteStartElement(string title, IDictionary<string, string> attribs)
        {
            try
            {
                var info = new TraceInfo(title, attribs);

                var ensureMaxXmlFiles = false;
                if (String.IsNullOrEmpty(_file))
                {
                    ensureMaxXmlFiles = true;

                    // generate trace file name base on attribs
                    _file = GenerateFileName(info);
                }

                var strb = new StringBuilder();

                if (_isStartElement)
                {
                    strb.AppendLine(">");
                }

                strb.Append(new String(' ', _infos.Count * 2));
                strb.AppendFormat("<step title=\"{0}\" ", XmlUtility.EscapeXmlText(title));
                strb.AppendFormat("date=\"{0}\" ", info.StartTime.ToString("yyyy-MM-ddTHH:mm:ss.fff"));
                if (_infos.Count == 0)
                {
                    strb.AppendFormat("instance=\"{0}\" ", InstanceIdUtility.GetShortInstanceId());
                }

                foreach (var attrib in attribs)
                {
                    if (TraceExtensions.IsNonDisplayableAttribute(attrib.Key))
                    {
                        continue;
                    }

                    strb.AppendFormat("{0}=\"{1}\" ", attrib.Key, XmlUtility.EscapeXmlText(attrib.Value));
                }

                FileSystemHelpers.AppendAllTextToFile(_file, strb.ToString());
                _infos.Push(info);
                _isStartElement = true;

                if (ensureMaxXmlFiles)
                {
                    EnsureMaxXmlFiles();
                }
{'fraction_non_alphanumeric': 0.0839112343966713, 'fraction_numerical': 0.0034674063800277394, 'mean_word_length': 1.7065999374413512, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '641672', 'n_tokens_mistral': 2222, 'n_tokens_neox': 2091, 'n_words': 562}