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}"; }) )); }
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}"; }) )); }
/// <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);
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); }