// TODO This eventually needs to be moved to its own Consumer so event is not decoded more than once.
        private void WriteEventToCsvAndTableFiles(EventRecord eventRecord, string lttUnstructuredTextEventString, string taskNameEventNameFromUnstructured, bool isUnstructuredLtt, StreamWriter fileStreamDtr, StreamWriter fileStreamTable)
        {
            DecodedEtwEvent decodedEvent;
            string          taskNameEventName = taskNameEventNameFromUnstructured;

            decodedEvent.StringRepresentation = null;
            bool decodingFailed = false;

            // Test whether event needs to be decoded.
            if (!isUnstructuredLtt)
            {
                try
                {
                    string originalEventName;
                    if (false == this.DecodeEvent(ref eventRecord, out decodedEvent, out originalEventName))
                    {
                        // Our attempt to decode the event failed
                        decodingFailed = true;
                    }

                    // TODO - to be removed after transitioning for structured traces in Linux
                    taskNameEventName = $"{decodedEvent.TaskName}.{originalEventName}";
                }
                catch (Exception e)
                {
                    this.traceSource.WriteError(
                        this.logSourceId,
                        "Exception encountered while decoding ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}. Exception information: {3}",
                        eventRecord.EventHeader.EventDescriptor.Id,
                        eventRecord.EventHeader.EventDescriptor.Task,
                        eventRecord.EventHeader.EventDescriptor.Level,
                        e);
                    decodingFailed = true;
                }
            }
            else
            {
                // legacy Service Fabric traces which consisted only of Unstructured traces.
                decodedEvent = new DecodedEtwEvent()
                {
                    StringRepresentation = lttUnstructuredTextEventString
                };
            }

            if (false == decodingFailed)
            {
                // Our attempt to decode the event succeeded. Put it
                // writing to dtr file
                string replacedLFStringRepresentation = decodedEvent.StringRepresentation.Replace("\r\n", "\r\t").Replace("\n", "\t");

                fileStreamDtr.Write(replacedLFStringRepresentation);
                fileStreamDtr.Write("\r\n");

                if (fileStreamTable != null && this.tableEventsWhiteList.Contains(taskNameEventName))
                {
                    fileStreamTable.Write(replacedLFStringRepresentation);
                    fileStreamTable.Write("\r\n");
                }
            }
        }
        private bool DecodeEvent(ref EventRecord eventRecord, out DecodedEtwEvent decodedEvent, out string originalEventName)
        {
            decodedEvent = new DecodedEtwEvent {
                EventRecord = eventRecord
            };
            originalEventName = string.Empty;

            if (false == ManifestCache.IsStringEvent(eventRecord))
            {
                var eventDefinition = this.etwManifestCache.GetEventDefinition(
                    eventRecord);
                if (null == eventDefinition)
                {
                    if (eventRecord.EventHeader.EventDescriptor.Task != (ushort)FabricEvents.EventSourceTaskId)
                    {
                        // We couldn't decode this event. Skip it.
                        this.traceSource.WriteError(
                            this.logSourceId,
                            "Unable to decode ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}.",
                            eventRecord.EventHeader.EventDescriptor.Id,
                            eventRecord.EventHeader.EventDescriptor.Task,
                            eventRecord.EventHeader.EventDescriptor.Level);
                    }

                    return(false);
                }

                if (eventDefinition.IsChildEvent)
                {
                    // Try to format the event. This causes the ETL reader to save information
                    // about this event. That information is later retrieved when the parent
                    // event is processed.
                    string childEventType;
                    string childEventText;
                    var    childStringRepresentation = this.etwManifestCache.FormatEvent(
                        eventRecord,
                        out childEventType,
                        out childEventText);

                    // Only parent events can be decoded. Child events supply additional
                    // information about the parent event and cannot be decoded on their
                    // own.
                    return(false);
                }

                decodedEvent.TaskName = eventDefinition.TaskName;
                originalEventName     = eventDefinition.OriginalEventName;
            }
            else
            {
                decodedEvent.TaskName = EventFormatter.StringEventTaskName;
            }

            decodedEvent.Timestamp            = DateTime.FromFileTimeUtc(eventRecord.EventHeader.TimeStamp);
            decodedEvent.Level                = eventRecord.EventHeader.EventDescriptor.Level;
            decodedEvent.ThreadId             = eventRecord.EventHeader.ThreadId;
            decodedEvent.ProcessId            = eventRecord.EventHeader.ProcessId;
            decodedEvent.StringRepresentation = this.etwManifestCache.FormatEvent(
                eventRecord,
                out decodedEvent.EventType,
                out decodedEvent.EventText,
                0);
            if (null == decodedEvent.StringRepresentation)
            {
                if (eventRecord.EventHeader.EventDescriptor.Task != (ushort)FabricEvents.EventSourceTaskId)
                {
                    // We couldn't decode this event. Skip it.
                    this.traceSource.WriteError(
                        this.logSourceId,
                        "Unable to decode ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}.",
                        eventRecord.EventHeader.EventDescriptor.Id,
                        eventRecord.EventHeader.EventDescriptor.Task,
                        eventRecord.EventHeader.EventDescriptor.Level);
                    return(false);
                }
            }

            // in case it is a string event and the eventName is not give by the eventDefinition
            if (string.IsNullOrEmpty(originalEventName))
            {
                originalEventName = decodedEvent.EventType;
            }

            // If this is an FMM event, update the last timestamp of FMM events
            if (decodedEvent.TaskName.Equals(Utility.FmmTaskName))
            {
                Utility.LastFmmEventTimestamp = decodedEvent.Timestamp;
            }

            return(true);
        }
        // TODO - Uncomment code below when totally transitioned to structured traces
        private void DeliverEventToSinks(ref EventRecord eventRecord, StringBuilder unstructuredTextString, bool isUnstructured)
        {
            var decodedEvent      = new DecodedEtwEvent();
            var decodingAttempted = false;
            var decodingFailed    = false;

            List <EventRecord>     rawEventList     = null;
            List <DecodedEtwEvent> decodedEventList = null;

            foreach (var sink in this.sinksIEtlFile)
            {
                if (sink.NeedsDecodedEvent)
                {
                    // This consumer needs the decoded event
                    if (false == decodingAttempted)
                    {
                        // We haven't yet attempted to decode the event. Attempt
                        // it now.
                        // For handling Linux legacy unstructured traces only
                        if (isUnstructured == true)
                        {
                            decodedEvent.StringRepresentation = unstructuredTextString.ToString();
                            decodingFailed    = false;
                            decodingAttempted = true;
                        }
                        else
                        {
                            try
                            {
                                string unusedOriginalEventName;

                                if (false == this.DecodeEvent(ref eventRecord, out decodedEvent, out unusedOriginalEventName))
                                {
                                    // Our attempt to decode the event failed
                                    decodingFailed = true;
                                }
                            }
                            catch (Exception e)
                            {
                                this.traceSource.WriteError(
                                    this.logSourceId,
                                    "Exception encountered while decoding Ltt event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}. Exception information: {3}",
                                    eventRecord.EventHeader.EventDescriptor.Id,
                                    eventRecord.EventHeader.EventDescriptor.Task,
                                    eventRecord.EventHeader.EventDescriptor.Level,
                                    e);
                                decodingFailed = true;
                            }
                        }

                        if (false == decodingFailed)
                        {
                            // Our attempt to decode the event succeeded. Put it
                            // in the event list.
                            Debug.Assert(null == decodedEventList, "Decoded event list should not be initialized previously.");
                            decodedEventList = new List <DecodedEtwEvent> {
                                decodedEvent
                            };
                        }

                        decodingAttempted = true;
                    }

                    if (false == decodingFailed)
                    {
                        sink.OnEtwEventsAvailable(decodedEventList);
                    }
                }
                else
                {
                    if (isUnstructured == false)
                    {
                        // This consumer needs the raw event
                        if (null == rawEventList)
                        {
                            // Put the event in the event list
                            rawEventList = new List <EventRecord> {
                                eventRecord
                            };
                        }
                        if (sink is IEtlFileSink)
                        {
                            IEtlFileSink sinkEtl = sink as IEtlFileSink;
                            sinkEtl.OnEtwEventsAvailable(rawEventList);
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
        private void OnEtwTraceAvailable(EventRecord eventRecord)
        {
            if (null != this.appEtwGuids && this.appEtwGuids.Any())
            {
                if (false == this.appEtwGuids.Contains(
                        eventRecord.EventHeader.ProviderId))
                {
                    // This event is not interesting to the application instance
                    // for whom we are collecting data. Skip it.
                    return;
                }
            }

            var decodedEvent      = new DecodedEtwEvent();
            var decodingAttempted = false;
            var decodingFailed    = false;

            List <EventRecord>     rawEventList     = null;
            List <DecodedEtwEvent> decodedEventList = null;

            foreach (var sink in this.sinks)
            {
                if (sink.NeedsDecodedEvent)
                {
                    // This consumer needs the decoded event
                    if (false == decodingAttempted)
                    {
                        // We haven't yet attempted to decode the event. Attempt
                        // it now.
                        try
                        {
                            if (false == this.DecodeEvent(eventRecord, out decodedEvent))
                            {
                                // Our attempt to decode the event failed
                                decodingFailed = true;
                            }
                        }
                        catch (Exception e)
                        {
                            this.traceSource.WriteError(
                                this.logSourceId,
                                "Exception encountered while decoding ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}. Exception information: {3}",
                                eventRecord.EventHeader.EventDescriptor.Id,
                                eventRecord.EventHeader.EventDescriptor.Task,
                                eventRecord.EventHeader.EventDescriptor.Level,
                                e);
                            decodingFailed = true;
                        }

                        if (false == decodingFailed)
                        {
                            // Our attempt to decode the event succeeded. Put it
                            // in the event list.
                            Debug.Assert(null == decodedEventList, "Decoded event list should not be initialized previously.");
                            decodedEventList = new List <DecodedEtwEvent> {
                                decodedEvent
                            };
                        }

                        decodingAttempted = true;
                    }

                    if (false == decodingFailed)
                    {
                        sink.OnEtwEventsAvailable(decodedEventList);
                    }
                }
                else
                {
                    // This consumer needs the raw event
                    if (null == rawEventList)
                    {
                        // Put the event in the event list
                        rawEventList = new List <EventRecord> {
                            eventRecord
                        };
                    }

                    sink.OnEtwEventsAvailable(rawEventList);
                }
            }

            this.perfHelper.EtwEventProcessed();
        }
Exemplo n.º 5
0
        private bool DecodeEvent(EventRecord eventRecord, out DecodedEtwEvent decodedEvent)
        {
            decodedEvent = new DecodedEtwEvent {
                EventRecord = eventRecord
            };

            if (false == ManifestCache.IsStringEvent(eventRecord))
            {
                var eventDefinition = this.etwManifestCache.GetEventDefinition(
                    eventRecord);
                if (null == eventDefinition)
                {
                    if (!EventSourceHelper.CheckForDynamicManifest(eventRecord.EventHeader.EventDescriptor))
                    {
                        // We couldn't decode this event. Skip it.
                        this.traceSource.WriteError(
                            this.logSourceId,
                            "Unable to decode ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}.",
                            eventRecord.EventHeader.EventDescriptor.Id,
                            eventRecord.EventHeader.EventDescriptor.Task,
                            eventRecord.EventHeader.EventDescriptor.Level);
                    }

                    return(false);
                }

                if (eventDefinition.IsChildEvent)
                {
                    // Try to format the event. This causes the ETL reader to save information
                    // about this event. That information is later retrieved when the parent
                    // event is processed.
                    string childEventType;
                    string childEventText;
                    var    childStringRepresentation = this.etwManifestCache.FormatEvent(
                        eventRecord,
                        out childEventType,
                        out childEventText);

                    // Only parent events can be decoded. Child events supply additional
                    // information about the parent event and cannot be decoded on their
                    // own.
                    return(false);
                }

                decodedEvent.TaskName = eventDefinition.TaskName;
            }
            else
            {
                decodedEvent.TaskName = EventFormatter.StringEventTaskName;
            }

            decodedEvent.Timestamp            = DateTime.FromFileTimeUtc(eventRecord.EventHeader.TimeStamp);
            decodedEvent.Level                = eventRecord.EventHeader.EventDescriptor.Level;
            decodedEvent.ThreadId             = eventRecord.EventHeader.ThreadId;
            decodedEvent.ProcessId            = eventRecord.EventHeader.ProcessId;
            decodedEvent.StringRepresentation = this.etwManifestCache.FormatEvent(
                eventRecord,
                out decodedEvent.EventType,
                out decodedEvent.EventText);
            if (null == decodedEvent.StringRepresentation)
            {
                if (!EventSourceHelper.CheckForDynamicManifest(eventRecord.EventHeader.EventDescriptor))
                {
                    // We couldn't decode this event. Skip it.
                    this.traceSource.WriteError(
                        this.logSourceId,
                        "Unable to decode ETW event. The event will be skipped. Event ID: {0}, Task: {1}, Level: {2}.",
                        eventRecord.EventHeader.EventDescriptor.Id,
                        eventRecord.EventHeader.EventDescriptor.Task,
                        eventRecord.EventHeader.EventDescriptor.Level);
                    return(false);
                }
            }

            // If this is an FMM event, update the last timestamp of FMM events
            if ((WinFabricEtlType.DefaultEtl == this.windowsFabricEtlType) &&
                decodedEvent.TaskName.Equals(Utility.FmmTaskName))
            {
                Utility.LastFmmEventTimestamp = decodedEvent.Timestamp;
            }

            return(true);
        }
        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 bool ParseV2EventInfo(string fileName, string line, ref string lineV1, ref DecodedEtwEvent etwEventInfo)
        {
            // We pass in the maximum substring count to the Split method below, so that we
            // only parse the new V2 fields. The V1 fields will be parsed by our caller.
            string[] lineParts = line.Split(new char[] { ',' }, (int)EventLineV2Parts.Count);
            if (lineParts.Length != ((int)EventLineV2Parts.Count))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event did not have the expected number of comma separators.",
                    line,
                    fileName);
                return(false);
            }

            // Parse the V2 fields
            if (false == Guid.TryParse(
                    lineParts[(int)EventLineV2Parts.ProviderId],
                    out etwEventInfo.EventRecord.EventHeader.ProviderId))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The provider ID could not be parsed as a GUID.",
                    line,
                    fileName);
                return(false);
            }

            if (false == ushort.TryParse(
                    lineParts[(int)EventLineV2Parts.EventId],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Id))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event ID could not be parsed as a ushort data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == byte.TryParse(
                    lineParts[(int)EventLineV2Parts.EventVersion],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Version))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event version could not be parsed as a byte data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == byte.TryParse(
                    lineParts[(int)EventLineV2Parts.Channel],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Channel))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The channel could not be parsed as a byte data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == byte.TryParse(
                    lineParts[(int)EventLineV2Parts.Opcode],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Opcode))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The opcode could not be parsed as a byte data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == ushort.TryParse(
                    lineParts[(int)EventLineV2Parts.TaskId],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Task))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The task ID could not be parsed as a ushort data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == ulong.TryParse(
                    lineParts[(int)EventLineV2Parts.Keyword],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.EventRecord.EventHeader.EventDescriptor.Keyword))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event keyword could not be parsed as a ulong data type.",
                    line,
                    fileName);
                return(false);
            }

            // Leave the V1 part of this line for the caller to parse.
            lineV1 = lineParts[(int)EventLineV2Parts.V1Part];

            return(true);
        }
        private bool ParseEventInfo(string fileName, int version, string line, ref DecodedEtwEvent etwEventInfo, ref string nodeUniqueEventId)
        {
            string lineV1 = line;

            if (version > 1)
            {
                // The new fields added in V2 were added at the beginning. So parse them first.
                if (false == this.ParseV2EventInfo(fileName, line, ref lineV1, ref etwEventInfo))
                {
                    return(false);
                }
            }

            // The event text can also contain commas, so we pass in the maximum
            // substring count to the Split method below, so that the event text
            // does not get split.
            string[] lineParts = lineV1.Split(new[] { ',' }, (int)EventLineParts.Count);
            if (lineParts.Length != ((int)EventLineParts.Count))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event did not have the expected number of comma separators.",
                    line,
                    fileName);
                return(false);
            }

            nodeUniqueEventId = lineParts[(int)EventLineParts.UniqueId];
            long timestampBinary;

            if (false == long.TryParse(
                    lineParts[(int)EventLineParts.Timestamp],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out timestampBinary))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event timestamp could not be parsed as a long data type.",
                    line,
                    fileName);
                return(false);
            }

            etwEventInfo.Timestamp = DateTime.FromBinary(timestampBinary);

            if (false == byte.TryParse(
                    lineParts[(int)EventLineParts.Level],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.Level))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The event level could not be parsed as an byte data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == uint.TryParse(
                    lineParts[(int)EventLineParts.ThreadId],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.ThreadId))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The thread ID could not be parsed as an int data type.",
                    line,
                    fileName);
                return(false);
            }

            if (false == uint.TryParse(
                    lineParts[(int)EventLineParts.ProcessId],
                    NumberStyles.Integer,
                    CultureInfo.InvariantCulture,
                    out etwEventInfo.ProcessId))
            {
                this.TraceSource.WriteError(
                    this.LogSourceId,
                    "Event '{0}' in buffered event file {1} was not in the expected format. The process ID could not be parsed as an int data type.",
                    line,
                    fileName);
                return(false);
            }

            etwEventInfo.TaskName  = lineParts[(int)EventLineParts.TaskName];
            etwEventInfo.EventType = lineParts[(int)EventLineParts.EventType];
            etwEventInfo.EventText = lineParts[(int)EventLineParts.EventText];
            return(true);
        }
Exemplo n.º 9
0
 internal DecodedEventWrapper(DecodedEtwEvent producerEvent)
 {
     this.producerEvent = producerEvent;
 }
Exemplo n.º 10
0
        public void OnEtwEventAvailable(DecodedEtwEvent etwEvent, string nodeUniqueEventId)
        {
            // Create and initialize the entity to be written
            EtwEventEntity eventEntity = new EtwEventEntity();

            eventEntity.PartitionKey = this.initParam.FabricNodeId;
            // Prefix the row key with the event timestamp. This allows us to use the row key when
            // querying for old events, which makes old event deletion faster.
            eventEntity.RowKey = String.Concat(
                etwEvent.Timestamp.Ticks.ToString(
                    "D20",
                    CultureInfo.InvariantCulture),
                "_",
                nodeUniqueEventId);
            eventEntity.EventTimestamp      = etwEvent.Timestamp;
            eventEntity.Level               = etwEvent.Level;
            eventEntity.ThreadId            = (int)etwEvent.ThreadId;
            eventEntity.ProcessId           = (int)etwEvent.ProcessId;
            eventEntity.TaskName            = etwEvent.TaskName;
            eventEntity.EventType           = etwEvent.EventType;
            eventEntity.AzureNodeInstanceId = this.azureNodeInstanceId;
            eventEntity.EventText           = etwEvent.EventText;
            eventEntity.EventId             = etwEvent.EventRecord.EventHeader.EventDescriptor.Id;

            const int eventTextLengthWarningThreshold = 8192;

            if (eventEntity.EventText.Length > eventTextLengthWarningThreshold)
            {
                // The maximum transaction size for a batched transaction to Windows
                // Azure table storage is 4MB. The maximum number of entities in a
                // batch is 100. Therefore, on an average we have about 40KB per entity,
                // including the overhead incurred by headers and other formatting.
                // This should be more than enough for our log messages. However, if
                // we come across a particularly long message, we log a warning.
                this.traceSource.WriteWarning(
                    this.logSourceId,
                    "Encountered a long trace message. Several long messages in a batched transaction can cause the transaction size limit to be exceeded. Message length: {0}. Message information: {1},{2},{3},{4}.{5},{6}",
                    eventEntity.EventText.Length,
                    eventEntity.EventTimestamp,
                    eventEntity.ThreadId,
                    eventEntity.ProcessId,
                    eventEntity.TaskName,
                    eventEntity.EventType,
                    this.initParam.FabricNodeId);
            }

            if (this.batchConcurrencyCount == this.contextIndex)
            {
                // We need a service context object that we can use
                this.contextIndex = GetServiceContextIndex();
            }

            // If the entity is already being tracked in the table service context,
            // there is nothing more to be done
            if (this.unsavedEntities[this.contextIndex].Any(
                    e =>
            {
                return(e.PartitionKey.Equals(eventEntity.PartitionKey) &&
                       e.RowKey.Equals(eventEntity.RowKey));
            }))
            {
                return;
            }

            // Add entity to batched changes
            this.unsavedEntities[this.contextIndex].Add(eventEntity);

            // Save batched changes if necessary
            if (ShouldSaveBatchedChanges())
            {
                bool result = CommitBatchedChangesBegin();
                if (result)
                {
                    // The current service context cannot be used until the batched
                    // operation we started above is complete. So set the service
                    // context index to an invalid value, so that we try to use a
                    // different context next time.
                    this.contextIndex = this.batchConcurrencyCount;
                }
            }
        }