public static string FormatStringToUse(EventAttribute eventAttribute, EventExtendedMetadataAttribute extended)
        {
            if (extended == null)
            {
                return(eventAttribute.Message);
            }

            var newFormat = new StringBuilder();

            foreach (var field in EventExtendedMetadataAttribute.MetadataFields)
            {
                newFormat.Append(field.FormatString);
                newFormat.Append(", ");
            }

            newFormat.Append(
                ShiftFormatArguments(
                    eventAttribute.Message,
                    (ushort)EventExtendedMetadataAttribute.MetadataFields.Count));
            return(newFormat.ToString());
        }
Example #2
0
        public TraceEvent(
            IVariantEventWriter variantEventWriter,
            EventTask taskId,
            ushort eventId,
            string eventName,
            EventLevel level,
            EventOpcode opcode,
            EventChannel channel,
            EventKeywords keywords,
            string format,
            bool hasId,
            ProvisionalMetadataAttribute provisionalAttribute,
            int typeFieldIndex,
            EventExtendedMetadataAttribute extendedMetadataAttribute = null)
        {
            if (string.IsNullOrEmpty(eventName))
            {
                throw new ArgumentException(
                          StringResources.Error_EventNameNullOrEmpty,
                          "eventName");
            }

            // We need to apply a keyword mask to the keyword in order for it to show up
            // in the Windows Event Log. The mask that is applied depends on the channel
            // in which we want the event to show up.
            //
            // TODO: We are currently hard-coding the mask values, but this is not ideal
            // because we have reverse-engineered these values by looking at the header
            // file generated by mc.exe. The algorithm to determine these values is an
            // internal implementation detail of mc.exe. A better alternative would be
            // to get the mask value from the source file generated by mc.exe, instead
            // of hard-coding it as a constant here.
            ulong keywordMask = 0;

            switch (channel)
            {
            case EventChannel.Admin:
                keywordMask = AdminChannelKeywordMask;
                break;

            case EventChannel.Debug:
                keywordMask = DebugChannelKeywordMask;
                break;

            case EventChannel.Operational:
                keywordMask = OperationalChannelKeywordMask;
                break;
            }

            long keywordWithMask;

            unchecked
            {
                keywordWithMask = (long)((ulong)keywords | keywordMask | TestKeyword);
            }

            // We ignore the opcode field for now. Manifest generation does the same.
            this.descriptor = new GenericEventDescriptor(
                eventId,
                version,
                (byte)channel,
                (byte)level,
                0,
                (int)taskId,
                keywordWithMask);

            this.eventName      = eventName;
            this.taskId         = taskId;
            this.level          = level;
            this.filterStates   = new bool[(int)TraceSinkType.Max];
            this.samplingRatio  = 0;
            this.hasId          = hasId;
            this.typeFieldIndex = typeFieldIndex;
            this.format         = format;

            this.taskName =
                typeof(FabricEvents.Tasks).GetFields().Single(f => (EventTask)f.GetRawConstantValue() == taskId).Name;

            this.variantEventWriter = variantEventWriter;

            // By default, provisional feature is disabled during object initialization. This needs to be enabled
            // by calling the Update function.
            this.isProvisionalFeatureEnabled = false;

            this.provisionalData = provisionalAttribute;
            if (this.provisionalData != null)
            {
                this.isProvisionalEvent = true;
                this.provisionalCache   = AgeBasedCache <VariantId, Variant[]> .DefaultInstance;
                this.PopulatePositions();
            }

            for (TraceSinkType sink = 0; sink < TraceSinkType.Max; sink++)
            {
                var status   = TraceConfig.GetEventEnabledStatus(sink, this.level, this.taskId, this.eventName);
                var sampling = TraceConfig.GetEventSamplingRatio(sink, this.level, this.taskId, this.eventName);

                this.UpdateProvisionalFeatureStatus(sink, TraceConfig.GetEventProvisionalFeatureStatus(sink));
                this.UpdateSinkEnabledStatus(sink, status);
                this.UpdateSinkSamplingRatio(sink, sampling);
            }

#if DotNetCoreClrLinux
            // TODO - Following code will be removed once fully transitioned to structured traces in Linux
            this.linuxStructuredTracesEnabled = TraceConfig.GetLinuxStructuredTracesEnabled();
            TraceConfig.OnLinuxStructuredTracesEnabledUpdate += this.UpdateLinuxStructuredTracesEnabled;
#endif

            this.ExtendedMetadata = extendedMetadataAttribute;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="eventAttribute"></param>
        /// <param name="extended"></param>
        /// <returns></returns>
        public static ServiceFabricEventChannel ChannelToUse(EventAttribute eventAttribute, EventExtendedMetadataAttribute extended)
        {
            bool hasKeywordOperational = extended != null;

            if (hasKeywordOperational)
            {
                return(ServiceFabricEventChannel.Operational);
            }
            else
            {
                bool moreSevereThanWarningLevel = eventAttribute.Level < EventLevel.Warning;

                if (moreSevereThanWarningLevel)
                {
                    return(ServiceFabricEventChannel.Admin);
                }
                else
                {
                    return(ServiceFabricEventChannel.Debug);
                }
            }
        }
        protected ReadOnlyDictionary <int, TraceEvent> GenerateEventDescriptors(IVariantEventWriter variantEventWriter)
        {
            var eventDescriptors = new Dictionary <int, TraceEvent>();

            foreach (var eventMethod in this.GetType().GetMethods())
            {
                EventAttribute eventAttribute = (EventAttribute)eventMethod.GetCustomAttributes(typeof(EventAttribute), false).SingleOrDefault();

                if (eventAttribute == null)
                {
                    continue;
                }

                var hasId          = false;
                int typeFieldIndex = -1;
                var methodParams   = eventMethod.GetParameters().ToList();
                if (methodParams.Any())
                {
                    typeFieldIndex = methodParams.FindIndex(e => e.Name == "type");
                    hasId          = methodParams[0].Name == "id";
                }

                var eventId = (ushort)eventAttribute.EventId;

                ProvisionalMetadataAttribute   provisional = (ProvisionalMetadataAttribute)CustomAttributeExtensions.GetCustomAttributes(eventMethod, typeof(ProvisionalMetadataAttribute), false).SingleOrDefault();
                EventExtendedMetadataAttribute extended    = (EventExtendedMetadataAttribute)CustomAttributeExtensions.GetCustomAttributes(eventMethod, typeof(EventExtendedMetadataAttribute), false).SingleOrDefault();

                string eventName = eventMethod.Name;

                if (extended != null && extended.TableEntityKind != TableEntityKind.Unknown)
                {
                    eventName = string.Format(FabricEventSourceConstants.OperationalChannelEventNameFormat, extended.TableEntityKind, FabricEventSourceConstants.OperationalChannelTableNameSuffix, eventName);
                }

                eventDescriptors[eventId] = new TraceEvent(
                    variantEventWriter,
                    eventAttribute.Task,
                    eventId,
                    eventName,
                    eventAttribute.Level,
                    eventAttribute.Opcode,
                    ChannelToUse(eventAttribute, extended),
                    eventAttribute.Keywords,
                    FormatStringToUse(eventAttribute, extended),
                    hasId,
                    provisional,
                    typeFieldIndex,
                    extended);

                // Wire up TraceConfig filtering to event enabled status
                TraceConfig.OnFilterUpdate += sinkType =>
                {
                    eventDescriptors[eventId].UpdateSinkEnabledStatus(sinkType, TraceConfig.GetEventEnabledStatus(
                                                                          sinkType,
                                                                          eventDescriptors[eventId].Level,
                                                                          eventDescriptors[eventId].TaskId,
                                                                          eventDescriptors[eventId].EventName));

                    eventDescriptors[eventId].UpdateSinkSamplingRatio(sinkType, TraceConfig.GetEventSamplingRatio(
                                                                          sinkType,
                                                                          eventDescriptors[eventId].Level,
                                                                          eventDescriptors[eventId].TaskId,
                                                                          eventDescriptors[eventId].EventName));

                    eventDescriptors[eventId].UpdateProvisionalFeatureStatus(sinkType, TraceConfig.GetEventProvisionalFeatureStatus(sinkType));
                };
            }

            return(new ReadOnlyDictionary <int, TraceEvent>(eventDescriptors));
        }