Beispiel #1
0
 public void StartEvent(string eventName, EventAttribute eventAttribute)
 {
     this.eventName         = eventName;
     this.numParams         = 0;
     this.byteArrArgIndices = (List <int>)null;
     this.events.Append("  <event").Append(" value=\"").Append(eventAttribute.EventId).Append("\"").Append(" version=\"").Append(eventAttribute.Version).Append("\"").Append(" level=\"").Append(ManifestBuilder.GetLevelName(eventAttribute.Level)).Append("\"").Append(" symbol=\"").Append(eventName).Append("\"");
     this.WriteMessageAttrib(this.events, "event", eventName, eventAttribute.Message);
     if (eventAttribute.Keywords != EventKeywords.None)
     {
         this.events.Append(" keywords=\"").Append(this.GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append("\"");
     }
     if (eventAttribute.Opcode != EventOpcode.Info)
     {
         this.events.Append(" opcode=\"").Append(this.GetOpcodeName(eventAttribute.Opcode, eventName)).Append("\"");
     }
     if (eventAttribute.Task != EventTask.None)
     {
         this.events.Append(" task=\"").Append(this.GetTaskName(eventAttribute.Task, eventName)).Append("\"");
     }
     if (eventAttribute.Channel == EventChannel.None)
     {
         return;
     }
     this.events.Append(" channel=\"").Append(this.GetChannelName(eventAttribute.Channel, eventName, eventAttribute.Message)).Append("\"");
 }
        /// <summary>
        /// Returns an EventAttribute for the Completed or Faulted events for a call context.
        /// </summary>
        /// <param name="baseAttribute">The EventAttribute for the method call that should be copied.</param>
        /// <param name="context">The context of the call.</param>
        /// <param name="nextEventId">The next event ID to use if not specified by some other mechanism.</param>
        /// <returns>The EventAttribute for the call context.</returns>
        public virtual EventAttribute CopyEventAttribute(EventAttribute baseAttribute, InvocationContext context, int nextEventId)
        {
            if (baseAttribute == null) throw new ArgumentNullException("baseAttribute");
            if (context == null) throw new ArgumentNullException("context");

            return new EventAttribute(nextEventId)
            {
                Keywords = baseAttribute.Keywords,
                Level = GetEventLevelForContext(context, baseAttribute),
                Message = GetEventMessage(context),
                Opcode = baseAttribute.Opcode,
                Task = baseAttribute.Task,
                Version = baseAttribute.Version
            };
        }
        /// <summary>
        /// Converts an EventAttribute to a CustomAttributeBuilder so it can be assigned to a method.
        /// </summary>
        /// <param name="attribute">The attribute to copy.</param>
        /// <returns>A CustomAttributeBuilder that can be assigned to a method.</returns>
        internal static CustomAttributeBuilder ConvertEventAttributeToAttributeBuilder(EventAttribute attribute)
        {
            var propertyValues = new object[]
            {
                attribute.Keywords,
                attribute.Level,
                attribute.Message,
                attribute.Opcode,
                attribute.Task,
                attribute.Version
            };

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(
                _eventAttributeConstructor,
                new object[] { attribute.EventId },
                _eventAttributePropertyInfo,
                propertyValues);

            return attributeBuilder;
        }
        /// <summary>
        /// Emit a call to WriteEvent(param object[]).
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="methodBuilder">The MethodBuilder to append to.</param>
        /// <param name="eventAttribute">The EventAttribute to use as values in the method.</param>
        /// <param name="sourceParameterTypes">The types of parameters on the source method.</param>
        /// <param name="targetParameterTypes">The types of the parameters on the target method.</param>
        private void EmitCallWriteEvent(InvocationContext invocationContext, MethodBuilder methodBuilder, EventAttribute eventAttribute, Type[] sourceParameterTypes, Type[] targetParameterTypes)
        {
            ILGenerator mIL = methodBuilder.GetILGenerator();

            // if there is no event attribute, then this is a non-event, so just return silently
            if (eventAttribute == null)
            {
                ProxyHelper.EmitDefaultValue(mIL, methodBuilder.ReturnType);
                mIL.Emit(OpCodes.Ret);
                return;
            }

            // call write event with the parameters in an object array
            mIL.Emit(OpCodes.Ldarg_0);
            mIL.Emit(OpCodes.Ldc_I4, eventAttribute.EventId);

            // create a new array of the proper length to pass the values in
            mIL.Emit(OpCodes.Ldc_I4, targetParameterTypes.Length);
            mIL.Emit(OpCodes.Newarr, typeof(object));
            for (int i = 0; i < sourceParameterTypes.Length; i++)
            {
                mIL.Emit(OpCodes.Dup);
                mIL.Emit(OpCodes.Ldc_I4, (int)i);

                // load the argument and box it
                mIL.Emit(OpCodes.Ldarg, (int)i + 1);

                // if the target is a value type, then we can box the source type
                // and the CLR will apply conversions for us
                // at this point, all invalid types have been converted to strings in EmitDirectProxy
                // and references have been dereferenced
                if (targetParameterTypes[i].IsValueType)
                {
                    var sourceType = sourceParameterTypes[i];
                    if (sourceType.IsByRef)
                        sourceType = sourceType.GetElementType();
                    mIL.Emit(OpCodes.Box, sourceType);
                }

                mIL.Emit(OpCodes.Stelem, typeof(object));
            }

            // if there is a context, call the context provider and add the context parameter
            if (SupportsContext(invocationContext))
            {
                // load the array and index onto the stack
                mIL.Emit(OpCodes.Dup);
                mIL.Emit(OpCodes.Ldc_I4, (int)targetParameterTypes.Length - 1);

                // load the context provider
                mIL.Emit(OpCodes.Ldsfld, _contextProviderField);

                // get the invocation context from the array on the provider
                mIL.Emit(OpCodes.Ldsfld, _invocationContextsField);
                mIL.Emit(OpCodes.Ldc_I4, _invocationContexts.Count);
                mIL.Emit(OpCodes.Ldelem, typeof(InvocationContext));
                mIL.Emit(OpCodes.Callvirt, typeof(TraceContextProvider).GetMethod("ProvideContext"));
                _invocationContexts.Add(invocationContext);

                // put the result into the array
                mIL.Emit(OpCodes.Stelem, typeof(object));
            }

            // prepare for write event by setting the ETW activity ID
            mIL.Emit(OpCodes.Call, typeof(EventActivityScope).GetMethod("PrepareForWriteEvent"));

            // call writeevent
            mIL.Emit(OpCodes.Call, _writeEvent);
            mIL.Emit(OpCodes.Ret);
        }
        /// <summary>
        /// Emits the code to determine whether logging is enabled.
        /// For NonEvents, this emits the default return value to the method, and returns false here.
        /// </summary>
        /// <param name="methodBuilder">The MethodBuilder to implement.</param>
        /// <param name="eventAttribute">The EventAttribute.</param>
        /// <returns>True if events could possibly be enabled, false if this method is a NonEvent.</returns>
        private static bool EmitIsEnabled(MethodBuilder methodBuilder, EventAttribute eventAttribute)
        {
            /*
             * This method assumes that a default return value is already on the stack
             *
             * if a nonevent:
             *
             *		return (top of stack)
             *
             * if an event:
             *
             *		if (!IsEnabled(level, keywords)
             *		{
             *			return (top of stack)
             *		}
             *		else
             *			...whatever gets emitted next
             */

            ILGenerator mIL = methodBuilder.GetILGenerator();

            // if there is no event attribute, then this is a non-event, so just return silently
            if (eventAttribute == null)
            {
                mIL.Emit(OpCodes.Ret);
                return false;
            }

            // call IsEnabled with the given event level and keywords to check whether we should log
            mIL.Emit(OpCodes.Ldarg_0);
            mIL.Emit(OpCodes.Ldc_I4, (int)eventAttribute.Level);
            mIL.Emit(OpCodes.Ldc_I8, (long)eventAttribute.Keywords);
            mIL.Emit(OpCodes.Call, _isEnabled);
            Label enabledLabel = mIL.DefineLabel();
            mIL.Emit(OpCodes.Brtrue, enabledLabel);
            mIL.Emit(OpCodes.Ret);
            mIL.MarkLabel(enabledLabel);

            return true;
        }
Beispiel #6
0
        public void StartEvent(string eventName, EventAttribute eventAttribute)
        {
            Contract.Assert(numParams == 0);
            Contract.Assert(templateName == null);
            templateName = eventName + "Args";
            numParams = 0;

            events.Append("  <event").
                 Append(" value=\"").Append(eventAttribute.EventId).Append("\"").
                 Append(" version=\"").Append(eventAttribute.Version).Append("\"").
                 Append(" level=\"").Append(GetLevelName(eventAttribute.Level)).Append("\"");

            WriteMessageAttrib(events, "event", eventName, eventAttribute.Message);

            if (eventAttribute.Keywords != 0)
                events.Append(" keywords=\"").Append(GetKeywords((ulong)eventAttribute.Keywords, eventName)).Append("\"");
            if (eventAttribute.Opcode != 0)
                events.Append(" opcode=\"").Append(GetOpcodeName(eventAttribute.Opcode, eventName)).Append("\"");
            if (eventAttribute.Task != 0)
                events.Append(" task=\"").Append(GetTaskName(eventAttribute.Task, eventName)).Append("\"");
#if FEATURE_MANAGED_ETW_CHANNELS
            if (eventAttribute.Channel != 0)
                events.Append(" channel=\"").Append(GetChannelName(eventAttribute.Channel, eventName)).Append("\"");
#endif
        }
Beispiel #7
0
        // Helper used by code:CreateManifestAndDescriptors to find user mistakes like reusing an event
        // index for two distinct events etc.  Throws exceptions when it finds something wrong. 
        private static void DebugCheckEvent(ref Dictionary<string, string> eventsByName,
            EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute)
        {
            int eventArg = GetHelperCallFirstArg(method);
            if (eventArg >= 0 && eventAttribute.EventId != eventArg)
            {
                throw new ArgumentException(Environment.GetResourceString("EventSource_MismatchIdToWriteEvent", method.Name, eventAttribute.EventId, eventArg));
            }

            if (eventAttribute.EventId < eventData.Length && eventData[eventAttribute.EventId].Descriptor.EventId != 0)
            {
                throw new ArgumentException(Environment.GetResourceString("EventSource_EventIdReused", method.Name, eventAttribute.EventId));
            }

            if (eventsByName == null)
                eventsByName = new Dictionary<string, string>();

            if (eventsByName.ContainsKey(method.Name))
                throw new ArgumentException(Environment.GetResourceString("EventSource_EventNameReused", method.Name));

            eventsByName[method.Name] = method.Name;
        }
Beispiel #8
0
        // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method
        // with the code:EventAttribute 'eventAttribute'.  resourceManger may be null in which case we populate it
        // it is populated if we need to look up message resources
        private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName, 
                                EventAttribute eventAttribute, ParameterInfo[] eventParameters)
        {
            if (eventData == null || eventData.Length <= eventAttribute.EventId)
            {
                EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)];
                Array.Copy(eventData, newValues, eventData.Length);
                eventData = newValues;
            }

            eventData[eventAttribute.EventId].Descriptor = new System.Diagnostics.Tracing.EventDescriptor(
                    eventAttribute.EventId,
                    eventAttribute.Version,
#if FEATURE_MANAGED_ETW_CHANNELS
                    (byte)eventAttribute.Channel,
#else
                    (byte)0,
#endif
                    (byte)eventAttribute.Level,
                    (byte)eventAttribute.Opcode,
                    (int)eventAttribute.Task,
                    (long)((ulong)eventAttribute.Keywords | SessionMask.All.ToEventKeywords()));

            eventData[eventAttribute.EventId].Name = eventName;
            eventData[eventAttribute.EventId].Parameters = eventParameters;
            eventData[eventAttribute.EventId].Message = eventAttribute.Message;
        }
Beispiel #9
0
        // Use reflection to look at the attributes of a class, and generate a manifest for it (as UTF8) and
        // return the UTF8 bytes.  It also sets up the code:EventData structures needed to dispatch events
        // at run time.  'source' is the event source to place the descriptors.  If it is null,
        // then the descriptors are not creaed, and just the manifest is generated.  
        private static byte[] CreateManifestAndDescriptors(Type eventSourceType, string eventSourceDllName, EventSource source)
        {
            MethodInfo[] methods = eventSourceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            EventAttribute defaultEventAttribute;
            int eventId = 1;        // The number given to an event that does not have a explicitly given ID. 
            EventMetadata[] eventData = null;
            Dictionary<string, string> eventsByName = null;
            if (source != null)
                eventData = new EventMetadata[methods.Length];

            // See if we have localization information.  
            ResourceManager resources = null;
            EventSourceAttribute eventSourceAttrib = (EventSourceAttribute)GetCustomAttributeHelper(eventSourceType, typeof(EventSourceAttribute));
            if (eventSourceAttrib != null && eventSourceAttrib.LocalizationResources != null)
                resources = new ResourceManager(eventSourceAttrib.LocalizationResources, eventSourceType.Assembly);

            ManifestBuilder manifest = new ManifestBuilder(GetName(eventSourceType), GetGuid(eventSourceType), eventSourceDllName, resources);

            // Collect task, opcode, keyword and channel information
#if FEATURE_MANAGED_ETW_CHANNELS
            foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes", "Channels" })
#else
            foreach (var providerEnumKind in new string[] { "Keywords", "Tasks", "Opcodes" })
#endif
            {
                Type nestedType = eventSourceType.GetNestedType(providerEnumKind);
                if (nestedType != null)
                {
                    foreach (FieldInfo staticField in nestedType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
                    {
                        AddProviderEnumKind(manifest, staticField, providerEnumKind);
                    }
                }
            }

            for (int i = 0; i < methods.Length; i++)
            {
                MethodInfo method = methods[i];
                ParameterInfo[] args = method.GetParameters();

                // Get the EventDescriptor (from the Custom attributes)
                EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute));

                // Methods that don't return void can't be events.  
                if (method.ReturnType != typeof(void))
                {
                    if (eventAttribute != null)
                        throw new ArgumentException(Environment.GetResourceString("EventSource_AttributeOnNonVoid", method.Name));
                    continue;
                }
                if (method.IsVirtual || method.IsStatic)
                {
                    continue;
                }

                if (eventAttribute == null)
                {
                    // If we explictly mark the method as not being an event, then honor that.  
                    if (GetCustomAttributeHelper(method, typeof(NonEventAttribute)) != null)
                        continue;

                    defaultEventAttribute = new EventAttribute(eventId);
                    eventAttribute = defaultEventAttribute;
                }
                else if (eventAttribute.EventId <= 0)
                    throw new ArgumentException(Environment.GetResourceString("EventSource_NeedPositiveId"));
                else if ((ulong)eventAttribute.Keywords >= 0x0000100000000000UL)
                    throw new ArgumentException(Environment.GetResourceString("EventSource_ReservedKeywords"));
                eventId++;

                // Auto-assign tasks, starting with the highest task number and working back 
                if (eventAttribute.Opcode == EventOpcode.Info && eventAttribute.Task == EventTask.None)
                    eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId);

                manifest.StartEvent(method.Name, eventAttribute);
                for (int fieldIdx = 0; fieldIdx < args.Length; fieldIdx++)
                {
                    // If the first parameter is 'RelatedActivityId' then skip it.  
                    if (fieldIdx == 0 && args[fieldIdx].ParameterType == typeof(Guid) && 
                        string.Compare(args[fieldIdx].Name, "RelatedActivityId", StringComparison.OrdinalIgnoreCase) == 0)
                        continue;
                    manifest.AddEventParameter(args[fieldIdx].ParameterType, args[fieldIdx].Name);
                }
                manifest.EndEvent();

                if (source != null)
                {
                    // Do checking for user errors (optional, but nto a big deal so we do it).  
                    DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute);
                    AddEventDescriptor(ref eventData, method.Name, eventAttribute, args);
                }
            }

            if (source != null)
            {
                TrimEventDescriptors(ref eventData);
                source.m_eventData = eventData;     // officaly initialize it. We do this at most once (it is racy otherwise). 
            }

            return manifest.CreateManifest();
        }
        /// <summary>
        /// Gets the appropriate EventLevel for the call context.
        /// </summary>
        /// <param name="context">The context of the call.</param>
        /// <param name="baseAttribute">The base attribute to copy if there are no additional attributes.</param>
        /// <returns>The EventLevel for the call context.</returns>
        protected virtual EventLevel GetEventLevelForContext(InvocationContext context, EventAttribute baseAttribute)
        {
            if (context == null) throw new ArgumentNullException("context");

            // for faulted methods, allow the EventExceptionAttribute to override the event level
            if (context.ContextType == InvocationContextTypes.MethodFaulted)
            {
                var attribute = context.MethodInfo.GetCustomAttribute<EventExceptionAttribute>();
                if (attribute != null)
                    return attribute.Level;

                attribute = context.MethodInfo.DeclaringType.GetCustomAttribute<EventExceptionAttribute>();
                if (attribute != null)
                    return attribute.Level;

                return ExceptionEventLevel;
            }

            // check for an attribute on the type
            var implementationAttribute = context.MethodInfo.DeclaringType.GetCustomAttribute<EventSourceImplementationAttribute>();
            if (implementationAttribute != null && implementationAttribute.Level.HasValue)
                return implementationAttribute.Level.Value;

            if (baseAttribute != null)
                return baseAttribute.Level;

            return EventLevel;
        }
		private static void ValidateEventMessage(EventAttribute eventAttribute, MethodInfo method, List<ParameterMapping> parameters)
		{
			if (eventAttribute == null)
				return;

			var message = eventAttribute.Message;
			if (message == null)
				return;

			object[] defaultValues = parameters.Select(p => GetDefaultStringFormatValue(p.TargetType)).ToArray();

			try
			{
				string.Format(CultureInfo.InvariantCulture, message, defaultValues);
			}
			catch (FormatException e)
			{
				throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid string format in Log Method {0}", method.Name), e);
			}
		}
		/// <summary>
		/// Emit a call to WriteEvent(param object[]).
		/// </summary>
		/// <param name="invocationContext">The InvocationContext for this call.</param>
		/// <param name="methodBuilder">The MethodBuilder to append to.</param>
		/// <param name="eventAttribute">The EventAttribute to use as values in the method.</param>
		/// <param name="parameterMapping">The mapping of the parameters.</param>
		private void EmitCallWriteEvent(InvocationContext invocationContext, MethodBuilder methodBuilder, EventAttribute eventAttribute, List<ParameterMapping> parameterMapping)
		{
			ILGenerator mIL = methodBuilder.GetILGenerator();

			// if there is no event attribute, then this is a non-event, so just return silently
			if (eventAttribute == null)
			{
				ProxyHelper.EmitDefaultValue(mIL, methodBuilder.ReturnType);
				mIL.Emit(OpCodes.Ret);
				return;
			}

			// call write event with the parameters in an object array
			mIL.Emit(OpCodes.Ldarg_0);
			mIL.Emit(OpCodes.Ldc_I4, eventAttribute.EventId);

			// create a new array of the proper length to pass the values in
			if (parameterMapping.Count > 0)
			{
				mIL.Emit(OpCodes.Ldc_I4, parameterMapping.Count);
				mIL.Emit(OpCodes.Newarr, typeof(object));
			}

			for (int i = 0; i < parameterMapping.Count; i++)
			{
				mIL.Emit(OpCodes.Dup);
				mIL.Emit(OpCodes.Ldc_I4, (int)i);

				var parameter = parameterMapping[i];

				if (parameter.HasSource)
				{
					// load the argument and box it
					mIL.Emit(OpCodes.Ldarg, i + 1);

					// if the target is a value type, then we can box the source type
					// and the CLR will apply conversions for us
					// at this point, all invalid types have been converted to strings in EmitDirectProxy
					// and references have been dereferenced
					if (parameter.CleanTargetType.IsValueType)
					{
						var sourceType = parameter.SourceType;
						if (sourceType.IsByRef)
							sourceType = sourceType.GetElementType();
						mIL.Emit(OpCodes.Box, sourceType);
					}
				}
				else
				{
					// there is no source, so get the context from the context provider
					// load the context provider
					mIL.Emit(OpCodes.Ldsfld, _contextProviderField);

					// get the invocation context from the array on the provider
					mIL.Emit(OpCodes.Ldsfld, _invocationContextsField);
					mIL.Emit(OpCodes.Ldc_I4, _invocationContexts.Count);
					mIL.Emit(OpCodes.Ldelem, typeof(InvocationContext));
					mIL.Emit(OpCodes.Callvirt, typeof(TraceContextProvider).GetMethod("ProvideContext"));
					_invocationContexts.Add(invocationContext);
				}

				mIL.Emit(OpCodes.Stelem, typeof(object));
			}

			// prepare for write event by setting the ETW activity ID
			mIL.Emit(OpCodes.Call, typeof(EventActivityScope).GetMethod("PrepareForWriteEvent"));

			// call writeevent
			mIL.Emit(OpCodes.Call, parameterMapping.Count == 0 ? _writeEventNoParams : _writeEvent);
			mIL.Emit(OpCodes.Ret);
		}