예제 #1
0
        public static string GenerateArgumentString(LoggingSite site, bool includeContext)
        {
            var contextArgument = includeContext
               ? site.LoggingContextParameterName + (site.Payload.Any() ? ", " : string.Empty)
               : string.Empty;

            return(contextArgument + string.Join(", ", site.Payload.Select(
                                                     parameter =>
            {
                var modifier = parameter.RefKind == RefKind.Ref ? "ref" : string.Empty;
                return $"{modifier} {parameter.Name}";
            })
                                                 ));
        }
예제 #2
0
        public static string GenerateParameterString(LoggingSite site, bool includeContext)
        {
            var contextParameter = includeContext
                ? I($"{GlobalInstrumentationNamespace}.LoggingContext {site.LoggingContextParameterName}") + (site.Payload.Any() ? ", " : string.Empty)
                : string.Empty;

            return(contextParameter + string.Join(", ", site.Payload.Select(
                                                      parameter =>
            {
                var modifier = parameter.RefKind == RefKind.Ref ? "ref" : string.Empty;
                var typeValue = parameter.Type.ToDisplayString();
                var defaultValue = parameter.HasExplicitDefaultValue
                        ? " = " + (parameter.ExplicitDefaultValue == null ? "null" : parameter.ExplicitDefaultValue.ToString())
                        : string.Empty;
                return $"{modifier}{typeValue} {parameter.Name}{defaultValue}";
            })
                                                  ));
        }
예제 #3
0
 /// <summary>
 /// Writes to the body of the log method. This will be called for each <see cref="LoggingSite"/>
 /// </summary>
 public abstract void GenerateLogMethodBody(LoggingSite site, Func <string> getMessageExpression);
예제 #4
0
        private bool ParseAndValidateLogSite(IMethodSymbol method, AttributeData attributeData, out LoggingSite loggingSite)
        {
            loggingSite         = new LoggingSite();
            loggingSite.Aliases = this.m_configuration.Aliases;
            loggingSite.Method  = method;

            if (!loggingSite.SetPayload(m_errorReport, method.Parameters.Skip(1)))
            {
                return(false);
            }

            // Pull the data out of the GeneratedEventAttribute
            foreach (var argument in attributeData.NamedArguments)
            {
                switch (argument.Key)
                {
                case "EventLevel":
                    if (argument.Value.Value.GetType() != typeof(int))
                    {
                        m_errorReport.ReportError(method, "Unsupported EventLevel value '{0}'", argument.Value.Value.ToString());
                        return(false);
                    }

                    int value = (int)argument.Value.Value;
                    switch (value)
                    {
                    case 0:
                        loggingSite.Level = Level.LogAlways;
                        break;

                    case 1:
                        loggingSite.Level = Level.Critical;
                        break;

                    case 2:
                        loggingSite.Level = Level.Error;
                        break;

                    case 3:
                        loggingSite.Level = Level.Warning;
                        break;

                    case 4:
                        loggingSite.Level = Level.Informational;
                        break;

                    case 5:
                        loggingSite.Level = Level.Verbose;
                        break;

                    default:
                        m_errorReport.ReportError(method, "Unsupported EventLevel value '{0}'", value);
                        break;
                    }

                    break;

                case "EventGenerators":
                    loggingSite.EventGenerators = (EventGenerators)argument.Value.Value;
                    break;

                case "Message":
                    loggingSite.SpecifiedMessageFormat = EscapeMessageString((string)argument.Value.Value);
                    break;

                case "EventOpcode":
                    loggingSite.EventOpcode = (byte)argument.Value.Value;
                    break;

                case "Keywords":
                    loggingSite.EventKeywords = (int)argument.Value.Value;
                    break;

                case "EventTask":
                    loggingSite.EventTask = (ushort)argument.Value.Value;
                    break;
                }
            }

            if (string.IsNullOrWhiteSpace(loggingSite.SpecifiedMessageFormat))
            {
                m_errorReport.ReportError(method, "Message is required");
                return(false);
            }

            if (loggingSite.SpecifiedMessageFormat.StartsWith(Events.LabeledProvenancePrefix, StringComparison.Ordinal) && method.Parameters.Length >= 2 && method.Parameters[1].Name != "location")
            {
                m_errorReport.ReportError(method, "Message is using provenance prefix information to indicate line information. Therefore the location must be the first parameter after the LoggingContext. This method declares '{0}' as that parameter", method.Parameters[1].Name);
                return(false);
            }

            // Verify the message format
            string normalizedMessageFormat = loggingSite.GetNormalizedMessageFormat();

            normalizedMessageFormat = normalizedMessageFormat.Replace("{{", string.Empty).Replace("}}", string.Empty);
            int openBracketPos  = -1;
            int curlyBracketPos = normalizedMessageFormat.IndexOfAny(new char[] { '{', '}' });

            while (curlyBracketPos >= 0)
            {
                if (openBracketPos < 0)
                {
                    if (normalizedMessageFormat[curlyBracketPos] == '}')
                    {
                        m_errorReport.ReportError(method, "Message format error: Found '}}' without matching '{{'");
                        return(false);
                    }

                    openBracketPos = curlyBracketPos;
                }
                else
                {
                    if (normalizedMessageFormat[curlyBracketPos] == '{')
                    {
                        m_errorReport.ReportError(method, "Message format error: Found too many nested '{{'");
                        return(false);
                    }

                    string format = normalizedMessageFormat.Substring(openBracketPos + 1, curlyBracketPos - openBracketPos - 1);
                    int    idx;
                    if (!int.TryParse(format.Split(':')[0], out idx))
                    {
                        m_errorReport.ReportError(method, "Message format error: Unknown parameter: {{{0}}}", format);
                        return(false);
                    }

                    if (idx < 0 || idx >= loggingSite.FlattenedPayload.Count)
                    {
                        m_errorReport.ReportError(method, "Message format error: Index out of range: {{{0}}}", format);
                        return(false);
                    }

                    openBracketPos = -1;
                }

                curlyBracketPos = normalizedMessageFormat.IndexOfAny(new char[] { '{', '}' }, curlyBracketPos + 1);
            }

            if (openBracketPos >= 0)
            {
                m_errorReport.ReportError(method, "Message format error: Found '{{' without matching '}}'");
                return(false);
            }

            // Only perform this check if telemetry is turned on. Otherwise events that only send to telemetry will
            // trigger the error
            if (loggingSite.EventGenerators == EventGenerators.None)
            {
                m_errorReport.ReportError(method, "EventGenerators not specified");
                return(false);
            }

            if (attributeData.ConstructorArguments.Length > 0 && attributeData.ConstructorArguments[0].Value.GetType() == typeof(ushort))
            {
                loggingSite.Id = (ushort)attributeData.ConstructorArguments[0].Value;
            }
            else
            {
                m_errorReport.ReportError(method, "First constructor argument should be an ushort");
                return(false);
            }

            if (method.Parameters.Length > 0 && method.Parameters[0].Type.Name == "LoggingContext")
            {
                loggingSite.LoggingContextParameterName = method.Parameters[0].Name;
            }
            else
            {
                m_errorReport.ReportError(method, "First method argument must be a LoggingContext");
                return(false);
            }

            foreach (AttributeData attribute in method.ContainingType.GetAttributes())
            {
                switch (attribute.AttributeClass.Name)
                {
                case "EventKeywordsTypeAttribute":
                    loggingSite.KeywordsType = (INamedTypeSymbol)attribute.ConstructorArguments[0].Value;
                    break;

                case "EventTasksTypeAttribute":
                    loggingSite.TasksType = (INamedTypeSymbol)attribute.ConstructorArguments[0].Value;
                    break;
                }
            }

            return(true);
        }