private void DeleteOldLogsHandler(object state)
        {
            this.TraceSource.WriteInfo(
                this.LogSourceId,
                "Starting deletion of old logs in directory {0} ...",
                this.etwEventCache);

            // Figure out the timestamp before which all files will be deleted
            DateTime cutoffTime = DateTime.UtcNow.Add(-this.eventDeletionAge);

            // Delete the files that are old enough to be deleted
            Utility.DeleteOldFilesFromFolder(
                this.LogSourceId,
                this.etwEventCache,
                null,
                cutoffTime,
                () => { return(this.Stopping); },
                false);

            this.TraceSource.WriteInfo(
                this.LogSourceId,
                "Finished deletion of old logs in directory {0}.",
                this.etwEventCache);

            // Schedule the next pass
            this.oldLogDeletionTimer.Start();
        }
        private string CreateEtwLogDirectory()
        {
            string etwParentFolder = Path.Combine(
                this.initParam.WorkDirectory,
                Utility.ShortWindowsFabricIdForPaths);

            string destinationKey = Path.Combine(
                this.mdsFileProducerSettings.DirectoryName,
                this.mdsFileProducerSettings.TableName);

            string etwFolder;
            bool   success = Utility.CreateWorkSubDirectory(
                this.traceSource,
                this.logSourceId,
                destinationKey,
                string.Concat(Utility.EtwConsumerWorkSubFolderIdPrefix, this.logSourceId),
                etwParentFolder,
                out etwFolder);

            if (success)
            {
                return(Path.Combine(etwFolder, LogDirName));
            }

            return(null);
        }
 private static void ReadLineFromFile(LineParam lineParam)
 {
     Utility.PerformIOWithRetries(
         ctx =>
     {
         LineParam param = ctx;
         param.Line      = param.Reader.ReadLine();
     },
         lineParam);
 }
        internal void OnEtlFileReadStop(string fileName, bool isActiveEtl, string currentBookmark, string nextBookmark, bool fileReadAborted)
        {
            if (null == this.streamWriter)
            {
                // An error occurred during the creation of the buffered event
                // file. So just return immediately without doing anything.
                return;
            }

            if (false == fileReadAborted)
            {
                // Flush pending events
                this.FlushPendingEvents(isActiveEtl, currentBookmark, nextBookmark);
            }

            // We're done processing an ETL file. Before this ETL file is moved
            // to the archives, make sure all the events we've written so far are
            // flushed to the buffered event file.
            try
            {
                Utility.PerformIOWithRetries(
                    () =>
                {
                    try
                    {
                        this.streamWriter.Flush();
                    }
                    catch (System.Text.EncoderFallbackException ex)
                    {
                        // This can happen if the manifest file does not match the binary.
                        // Write an error message and move on.
                        this.TraceSource.WriteError(
                            this.LogSourceId,
                            "Exception occurred while flushing filtered ETW events to buffered event file. Exception information: {0}",
                            ex);
                    }
                });
            }
            catch (Exception e)
            {
                // Log an error and move on
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to flush data to buffered event file.");
            }
        }
        private string CreateBlobUploaderWorkSubDirectory()
        {
            string workParentFolder = Path.Combine(
                this.initParam.WorkDirectory,
                Utility.ShortWindowsFabricIdForPaths);

            string workFolder;
            bool   success = Utility.CreateWorkSubDirectory(
                this.traceSource,
                this.logSourceId,
                this.destinationKey,
                this.etwLogDirName,
                workParentFolder,
                out workFolder);

            if (success)
            {
                return(Path.Combine(workFolder, AzureConstants.AzureFileUploaderFolder));
            }

            return(null);
        }
        private void ProcessEventsFromFile(string fileName)
        {
            this.TraceSource.WriteInfo(
                this.LogSourceId,
                "Processing ETW events from file {0}.",
                fileName);

            // Open the file
            ReadEventsFromFileParam readEventsParam = new ReadEventsFromFileParam();

            readEventsParam.StreamReader = null;
            readEventsParam.FileName     = fileName;
            try
            {
                Utility.PerformIOWithRetries(
                    this.OpenEtwEventCacheFile,
                    readEventsParam);
            }
            catch (Exception e)
            {
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to open file {0} for read.",
                    fileName);
                return;
            }

            if (readEventsParam.FileNotFound)
            {
                Debug.Assert(null == readEventsParam.StreamReader, "StreamReader should remain unset if file is not found.");
                return;
            }

            // Read and process events from the file
            try
            {
                // Check the DCA version to make sure we can parse this file
                int version;
                if (false == this.CanParseFile(readEventsParam.StreamReader, fileName, out version))
                {
                    return;
                }

                // Upload the ETW events that we just retrieved
                this.TraceSource.WriteInfo(
                    this.LogSourceId,
                    "Starting delivery of ETW events from file {0} ....",
                    fileName);

                LineParam lineParam = new LineParam();
                lineParam.Reader = readEventsParam.StreamReader;
                for (;;)
                {
                    // Read an event from the file
                    try
                    {
                        ReadLineFromFile(lineParam);
                    }
                    catch (Exception e)
                    {
                        this.TraceSource.WriteExceptionAsError(
                            this.LogSourceId,
                            e,
                            "Failed to read event from file {0}.",
                            fileName);
                        break;
                    }

                    if (null == lineParam.Line)
                    {
                        // End of file reached
                        break;
                    }

                    DecodedEtwEvent etwEventInfo      = new DecodedEtwEvent();
                    string          nodeUniqueEventId = null;
                    if (false == this.ParseEventInfo(fileName, version, lineParam.Line, ref etwEventInfo, ref nodeUniqueEventId))
                    {
                        // Couldn't parse this event, so skip it and continue with the
                        // remaining events.
                        continue;
                    }

                    // Deliver the event to the consumer
                    this.eventSink.OnEtwEventAvailable(etwEventInfo, nodeUniqueEventId);
                    this.perfHelper.EventDeliveredToConsumer();

                    // If the consumer has asked for the event delivery period to
                    // be aborted, then do so immediately.
                    if (this.eventDeliveryPeriodAborted)
                    {
                        this.TraceSource.WriteInfo(
                            this.LogSourceId,
                            "The event delivery pass is being aborted. Therefore, no more events will be read from file {0}.",
                            fileName);
                        break;
                    }

                    // If we are in the process of stopping, then don't process
                    // any more events
                    if (this.Stopping)
                    {
                        this.TraceSource.WriteInfo(
                            this.LogSourceId,
                            "The consumer is being stopped. Therefore, no more events will be read from file {0}.",
                            fileName);
                        break;
                    }
                }

                this.TraceSource.WriteInfo(
                    this.LogSourceId,
                    "Finished delivery of ETW events from file {0}.",
                    fileName);
            }
            finally
            {
                readEventsParam.StreamReader.Dispose();
            }
        }
        private void WriteTraceEvent(DecodedEventWrapper eventWrapper, string nodesUniqueEventId)
        {
            if (null == this.streamWriter)
            {
                // An error occurred during the creation of the buffered event
                // file. So just return immediately without doing anything.
                return;
            }

            // NOTE: The order in which the information is written must match
            // the order of the EventLineParts enumeration defined in this class.
            string eventInfo = string.Format(
                CultureInfo.InvariantCulture,
                "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}",
                eventWrapper.InternalEvent.EventRecord.EventHeader.ProviderId,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Id,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Version,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Channel,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Opcode,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Task,
                eventWrapper.InternalEvent.EventRecord.EventHeader.EventDescriptor.Keyword,
                nodesUniqueEventId,
                eventWrapper.Timestamp.ToBinary(),
                eventWrapper.Timestamp,                    // We write the human-readable form for easier debugging
                eventWrapper.Level,
                eventWrapper.ThreadId,
                eventWrapper.ProcessId,
                eventWrapper.TaskName,
                eventWrapper.EventType,
                eventWrapper.EventText);

            eventInfo = eventInfo.Replace("\r\n", "\t").Replace("\n", "\t").Replace("\r", "\t");
            try
            {
                Utility.PerformIOWithRetries(
                    ctx =>
                {
                    string eventString = ctx;
                    try
                    {
                        this.streamWriter.WriteLine(eventString);
                    }
                    catch (System.Text.EncoderFallbackException ex)
                    {
                        // This can happen if the manifest file does not match the binary.
                        // Write an error message and move on.
                        this.TraceSource.WriteError(
                            this.LogSourceId,
                            "Exception occurred while writing filtered ETW event to buffered event file. Exception information: {0}",
                            ex);
                    }
                },
                    eventInfo);
            }
            catch (Exception e)
            {
                // Log an error and move on
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to write ETW event to buffered event file.");
            }
        }
        public void OnEtwEventProcessingPeriodStop()
        {
            if (null == this.streamWriter)
            {
                // An error occurred during the creation of the buffered event
                // file. So just return immediately without doing anything.
                return;
            }

            // Close the buffered event file that we are currently working on.
            try
            {
                this.streamWriter.Dispose();
            }
            catch (System.Text.EncoderFallbackException ex)
            {
                // This can happen if the manifest file does not match the binary.
                // Write an error message and move on.
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Exception occurred while closing buffered event file. Exception information: {0}",
                    ex);
            }

            // Make our buffered event files available for delivery to the consumer.
            // This includes:
            //  - the buffered event file that we wrote in this pass
            //  - any old buffered event files that we wrote in previous passes
            //    (and got interrupted before we could rename them for delivery to
            //    the consumer).
            string[] cacheFiles = FabricDirectory.GetFiles(
                this.etwEventCache,
                TempCacheFileNameSearchPattern);
            foreach (string cacheFile in cacheFiles)
            {
                try
                {
                    Utility.PerformIOWithRetries(
                        ctx =>
                    {
                        string fileName = ctx;
                        FabricFile.Move(
                            fileName,
                            Path.ChangeExtension(fileName, CacheFileNameExtension));
                    },
                        cacheFile);

                    this.TraceSource.WriteInfo(
                        this.LogSourceId,
                        "File containing filtered ETW events was renamed for delivery to consumer. Old name: {0}, new name: {1}.",
                        cacheFile,
                        Path.ChangeExtension(cacheFile, CacheFileNameExtension));
                }
                catch (Exception e)
                {
                    this.TraceSource.WriteExceptionAsError(
                        this.LogSourceId,
                        e,
                        "Buffered event file {0} could not be renamed for delivery to consumer.",
                        cacheFile);
                }
            }

            this.perfHelper.EtlReadPassEnd();
        }
        public void OnEtwEventProcessingPeriodStart()
        {
            this.streamWriter = null;
            this.perfHelper.EtlReadPassBegin();

            // Build the full path to our buffered event file
            string tempCacheFileName = string.Format(
                CultureInfo.InvariantCulture,
                "{0}{1}.{2}",
                TempCacheFileNamePrefix,
                DateTime.Now.Ticks,
                TempCacheFileExtension);
            string tempCacheFileFullPath = Path.Combine(this.etwEventCache, tempCacheFileName);

            // Open the file
            StreamWriter writer = null;

            try
            {
                Utility.PerformIOWithRetries(
                    ctx =>
                {
                    string fileName       = ctx;
                    FileStream fileStream = FabricFile.Open(fileName, FileMode.Create, FileAccess.Write);
#if !DotNetCoreClr
                    Helpers.SetIoPriorityHint(fileStream.SafeFileHandle, Kernel32Types.PRIORITY_HINT.IoPriorityHintVeryLow);
#endif
                    writer = new StreamWriter(fileStream);
                },
                    tempCacheFileFullPath);
            }
            catch (Exception e)
            {
                // Log an error and move on. No events from this pass will be
                // written to the destination.
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to create a new file in the buffered event directory. None of the events from this pass will be written to the event buffer.");
                return;
            }

            // Write the version number. This will help us read data from the file.
            try
            {
                Utility.PerformIOWithRetries(
                    () =>
                {
                    writer.WriteLine(EtlConsumerConstants.EtwEventCacheFormatVersionString);
                });
            }
            catch (Exception e)
            {
                // Log an error and move on. No events from this pass will be
                // written to the destination.
                this.TraceSource.WriteExceptionAsError(
                    this.LogSourceId,
                    e,
                    "Failed to write buffered event file format version number to file {0} in the buffered event file. None of the events from this pass will be written to the event buffer.",
                    tempCacheFileFullPath);
                return;
            }

            this.streamWriter = writer;
            this.TraceSource.WriteInfo(
                this.LogSourceId,
                "Filtered ETW events for consumer will be buffered in file {0}.",
                tempCacheFileFullPath);
        }
        private void DeliverEventsToConsumer(object state)
        {
            this.perfHelper.EventDeliveryPassBegin();

            this.eventDeliveryPeriodAborted = false;

            // Perform any tasks necessary at the beginning of the event delivery pass
            this.eventSink.OnEtwEventDeliveryStart();

            // Get the files from the buffered event directory
            // We ignore files that are so old that they need to be deleted
            DateTime cutoffTime = DateTime.UtcNow.Add(-this.eventDeletionAge);

            DirectoryInfo dirInfo = new DirectoryInfo(this.etwEventCache);

            FileInfo[] eventFilesInfo = dirInfo.GetFiles(CacheFileNameSearchPattern)
                                        .Where(file => file.LastWriteTimeUtc.CompareTo(cutoffTime) > 0)
                                        .ToArray();

            // Sort the files such that the file with the most recent last-write
            // time comes first. We'll process files in that order so that in
            // case of huge backlogs the most recent (and hence likely to be
            // most interesting) traces are processed first.
            Array.Sort(eventFilesInfo, CompareFileLastWriteTimes);

            // Process each of the files
            int           filesProcessed    = 0;
            DateTime      processingEndTime = DateTime.Now.Add(this.eventDeliveryPassLength);
            List <string> filesToDelete     = new List <string>();

            foreach (FileInfo eventFileInfo in eventFilesInfo)
            {
                // Process events from the current file
                string eventFile = eventFileInfo.FullName;
                this.ProcessEventsFromFile(eventFile);
                filesProcessed++;

                // If the event delivery pass is being aborted, then don't process
                // any more files. Also, don't delete the current file because
                // its processing may have been interrupted. This file will be
                // processed again in the next pass.
                if (this.eventDeliveryPeriodAborted)
                {
                    this.TraceSource.WriteInfo(
                        this.LogSourceId,
                        "The event delivery pass is being aborted. Therefore, no more files in the buffered event directory will be processed.");
                    break;
                }

                // If we are in the process of stopping, then don't process any
                // more files. Also, don't delete the current file because its
                // processing may have been interrupted. This file will be
                // processed again when we are restarted.
                if (this.Stopping)
                {
                    this.TraceSource.WriteInfo(
                        this.LogSourceId,
                        "The consumer is being stopped. Therefore, no more files in the buffered event directory will be processed.");
                    break;
                }

                // Add the file to the list of files that we delete at the end
                // of the event delivery pass
                filesToDelete.Add(eventFile);

                if (0 > DateTime.Compare(processingEndTime, DateTime.Now))
                {
                    this.TraceSource.WriteInfo(
                        this.LogSourceId,
                        "Due to time limit on backlog processing, no more files in the buffered event directory will be processed in this pass.");
                    break;
                }
            }

            // Perform any tasks necessary at the end of the ETL processing pass
            this.eventSink.OnEtwEventDeliveryStop();

            // Delete the files that we successfully processed in this pass
            foreach (string fileToDelete in filesToDelete)
            {
                try
                {
                    Utility.PerformIOWithRetries(
                        ctx =>
                    {
                        string fileName = ctx;
                        FabricFile.Delete(fileName);
                    },
                        fileToDelete);
                }
                catch (Exception e)
                {
                    this.TraceSource.WriteExceptionAsError(
                        this.LogSourceId,
                        e,
                        "Failed to delete file {0}.",
                        fileToDelete);
                }
            }

            // Write performance-related information.
            this.perfHelper.RecordEventDeliveryBacklog(eventFilesInfo.Length - filesProcessed);
            this.perfHelper.EventDeliveryPassEnd();

            // Schedule the next pass
            this.eventDeliveryTimer.Start();
        }