/// <summary> /// Use this constructor when instantiating from a field. /// </summary> public MetricTag(FieldInfo fieldInfo, MetricTagAttribute attribute, Func <string, string> nameReplacer) { IsFromDefault = false; IsOptional = attribute.IsOptional; FieldInfo = fieldInfo; if (!FieldInfo.IsInitOnly || (FieldInfo.FieldType != typeof(string) && !FieldInfo.FieldType.IsEnum)) { throw new InvalidOperationException( $"The BosunTag attribute can only be applied to readonly string or enum fields. {fieldInfo.DeclaringType.FullName}.{fieldInfo.Name} is invalid."); } Attribute = attribute; if (attribute.Name != null) { Name = attribute.Name; } else if (nameReplacer != null) { Name = nameReplacer(fieldInfo.Name); } else { Name = fieldInfo.Name; } if (!MetricValidation.IsValidTagName(Name)) { throw new InvalidOperationException($"\"{Name}\" is not a valid Bosun Tag name. Field: {fieldInfo.DeclaringType.FullName}.{fieldInfo.Name}."); } }
/// <summary> /// Use this constructor when instantiating from a field or property. /// </summary> public MetricTag(MemberInfo memberInfo, MetricTagAttribute attribute, Func <string, string> nameReplacer) { switch (memberInfo) { case FieldInfo fieldInfo: if (!fieldInfo.IsInitOnly || (fieldInfo.FieldType != typeof(string) && !fieldInfo.FieldType.IsEnum)) { throw new InvalidOperationException( $"The MetricTag attribute can only be applied to readonly string or enum fields. {memberInfo.DeclaringType.FullName}.{memberInfo.Name} is invalid." ); } break; case PropertyInfo propertyInfo: if (propertyInfo.SetMethod != null || (propertyInfo.PropertyType != typeof(string) && !propertyInfo.PropertyType.IsEnum)) { throw new InvalidOperationException( $"The MetricTag attribute can only be applied to readonly string or enum properties. {memberInfo.DeclaringType.FullName}.{memberInfo.Name} is invalid." ); } break; default: throw new InvalidOperationException( $"The MetricTag attribute can only be applied to properties or fields. {memberInfo.DeclaringType.FullName}.{memberInfo.Name} is invalid." ); } IsFromDefault = false; IsOptional = attribute.IsOptional; MemberInfo = memberInfo; Attribute = attribute; if (attribute.Name != null) { Name = attribute.Name; } else if (nameReplacer != null) { Name = nameReplacer(memberInfo.Name); } else { Name = memberInfo.Name; } if (!MetricValidation.IsValidTagName(Name)) { throw new InvalidOperationException($"\"{Name}\" is not a valid tag name. Field: {memberInfo.DeclaringType.FullName}.{memberInfo.Name}."); } }
/// <summary> /// Applies an <see cref="AggregateMode"/> to an <see cref="AggregateGauge"/>. /// </summary> /// <param name="mode">The aggregate mode. Don't use AggregateMode.Percentile with this constructor.</param> /// <param name="suffix">Overrides the default suffix for the aggregate mode.</param> /// <param name="percentile"> /// The percentile represented as a double. For example, 0.95 = 95th percentile. Using more than two digits is not recommended. In order to use this /// argument, <paramref name="mode"/> must be AggregateMode.Percentile. /// </param> public GaugeAggregatorAttribute(AggregateMode mode, string suffix, double percentile) { AggregateMode = mode; Percentile = AggregateGauge.AggregateModeToPercentileAndSuffix(mode, percentile, out var defaultSuffix); Suffix = suffix ?? defaultSuffix; if (Suffix.Length > 0 && !MetricValidation.IsValidMetricName(Suffix)) { throw new Exception("\"" + Suffix + "\" is not a valid metric suffix."); } }
internal IReadOnlyDictionary <string, string> GetTags( IReadOnlyDictionary <string, string> defaultTags, TagValueConverterDelegate tagValueConverter, Func <string, string> propertyToTagConverter, Dictionary <Type, List <MetricTag> > tagsByTypeCache) { var tags = new Dictionary <string, string>(); foreach (var tag in GetTagsList(defaultTags, propertyToTagConverter, tagsByTypeCache)) { var value = tag.IsFromDefault ? defaultTags[tag.Name] : tag.GetValue(this); if (tagValueConverter != null) { value = tagValueConverter(tag.Name, value); } if (value == null) { if (tag.IsOptional) { continue; } throw new InvalidOperationException( $"null is not a valid tag value for {GetType().FullName}.{tag.MemberInfo.Name}. This tag was declared as non-optional."); } if (!MetricValidation.IsValidTagValue(value)) { throw new InvalidOperationException( $"Invalid value for tag {GetType().FullName}.{tag.MemberInfo.Name}. \"{value}\" is not a valid tag value. " + $"Only characters in the regex class [a-zA-Z0-9\\-_./] are allowed."); } tags.Add(tag.Name, value); } if (tags.Count == 0) { throw new InvalidOperationException( $"At least one tag value must be specified for every metric. {GetType().FullName} was instantiated without any tag values."); } return(tags); }