diff --git a/implementations/micrometer-registry-signalfx/src/main/java/io/micrometer/signalfx/SignalFxNamingConvention.java b/implementations/micrometer-registry-signalfx/src/main/java/io/micrometer/signalfx/SignalFxNamingConvention.java index 1e6e441a92..7429a4237d 100644 --- a/implementations/micrometer-registry-signalfx/src/main/java/io/micrometer/signalfx/SignalFxNamingConvention.java +++ b/implementations/micrometer-registry-signalfx/src/main/java/io/micrometer/signalfx/SignalFxNamingConvention.java @@ -22,17 +22,25 @@ import io.micrometer.core.instrument.util.StringEscapeUtils; import io.micrometer.core.instrument.util.StringUtils; import io.micrometer.core.lang.Nullable; +import io.micrometer.core.util.internal.logging.WarnThenDebugLogger; /** - * See https://developers.signalfx.com/reference#section-criteria-for-metric-and-dimension-names-and-values for criteria. + * {@link NamingConvention} for SignalFx. + * + * See https://developers.signalfx.com/metrics/data_ingest_overview.html#_criteria_for_metric_and_dimension_names_and_values * * @author Jon Schneider + * @author Johnny Lim */ public class SignalFxNamingConvention implements NamingConvention { + private static final WarnThenDebugLogger logger = new WarnThenDebugLogger(SignalFxNamingConvention.class); + private static final Pattern START_UNDERSCORE_PATTERN = Pattern.compile("^_"); private static final Pattern SF_PATTERN = Pattern.compile("^sf_"); private static final Pattern START_LETTERS_PATTERN = Pattern.compile("^[a-zA-Z].*"); + private static final Pattern PATTERN_TAG_KEY_BLACKLISTED_CHARS = Pattern.compile("[^\\w_\\-]"); + private static final Pattern PATTERN_TAG_KEY_BLACKLISTED_PREFIX = Pattern.compile("^(aws|gcp|azure)_.*"); private static final int NAME_MAX_LENGTH = 256; private static final int TAG_VALUE_MAX_LENGTH = 256; @@ -66,9 +74,16 @@ public String tagKey(String key) { conventionKey = START_UNDERSCORE_PATTERN.matcher(conventionKey).replaceAll(""); // 2 conventionKey = SF_PATTERN.matcher(conventionKey).replaceAll(""); // 2 + conventionKey = PATTERN_TAG_KEY_BLACKLISTED_CHARS.matcher(conventionKey).replaceAll("_"); if (!START_LETTERS_PATTERN.matcher(conventionKey).matches()) { // 3 conventionKey = "a" + conventionKey; } + if (PATTERN_TAG_KEY_BLACKLISTED_PREFIX.matcher(conventionKey).matches()) { + logger.log("'" + conventionKey + "' (original name: '" + key + "') is not a valid tag key. " + + "Must not start with any of these prefixes: aws_, gcp_, or azure_. " + + "Please rename it to conform to the constraints. " + + "If it comes from a third party, please use MeterFilter to rename it."); + } return StringUtils.truncate(conventionKey, KEY_MAX_LENGTH); // 1 } diff --git a/implementations/micrometer-registry-signalfx/src/test/java/io/micrometer/signalfx/SignalFxNamingConventionTest.java b/implementations/micrometer-registry-signalfx/src/test/java/io/micrometer/signalfx/SignalFxNamingConventionTest.java index 0e2b332577..706e959323 100644 --- a/implementations/micrometer-registry-signalfx/src/test/java/io/micrometer/signalfx/SignalFxNamingConventionTest.java +++ b/implementations/micrometer-registry-signalfx/src/test/java/io/micrometer/signalfx/SignalFxNamingConventionTest.java @@ -19,6 +19,12 @@ import static org.assertj.core.api.Assertions.assertThat; +/** + * Tests for {@link SignalFxNamingConvention}. + * + * @author Jon Schneider + * @author Johnny Lim + */ class SignalFxNamingConventionTest { private SignalFxNamingConvention convention = new SignalFxNamingConvention(); @@ -30,4 +36,9 @@ void tagKey() { assertThat(convention.tagKey("123")).isEqualTo("a123"); } -} \ No newline at end of file + @Test + void tagKeyWhenKeyHasBlacklistedCharShouldSanitize() { + assertThat(convention.tagKey("a.b")).isEqualTo("a_b"); + } + +}