From 1e8446eaa033037f341e59f7584bad646c099720 Mon Sep 17 00:00:00 2001
From: Aymerick Valette <valaymerick@gmail.com>
Date: Tue, 27 Apr 2021 18:29:28 +0200
Subject: [PATCH] subscriber: support special chars in span names (#1368)

Filtering log events using the `target[span{field=value}]=level` syntax
doesn't work when the span name contains a special char.

This PR closes #1367 by adding support for span names with any
characters other than `{` and `]` to `EnvFilter`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
---
 .../src/filter/env/directive.rs               | 32 ++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/tracing-subscriber/src/filter/env/directive.rs b/tracing-subscriber/src/filter/env/directive.rs
index 82c1eae3f1..fb1bd2f937 100644
--- a/tracing-subscriber/src/filter/env/directive.rs
+++ b/tracing-subscriber/src/filter/env/directive.rs
@@ -195,7 +195,7 @@ impl FromStr for Directive {
             )
             .unwrap();
             static ref SPAN_PART_RE: Regex =
-                Regex::new(r#"(?P<name>\w+)?(?:\{(?P<fields>[^\}]*)\})?"#).unwrap();
+                Regex::new(r#"(?P<name>[^\]\{]+)?(?:\{(?P<fields>[^\}]*)\})?"#).unwrap();
             static ref FIELD_FILTER_RE: Regex =
                 // TODO(eliza): this doesn't _currently_ handle value matchers that include comma
                 // characters. We should fix that.
@@ -1091,4 +1091,34 @@ mod test {
         assert_eq!(dirs[0].level, LevelFilter::INFO);
         assert_eq!(dirs[0].in_span, None);
     }
+
+    #[test]
+    fn parse_directives_with_dash_in_span_name() {
+        // Reproduces https://github.com/tokio-rs/tracing/issues/1367
+
+        let dirs = parse_directives("target[span-name]=info");
+        assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs);
+        assert_eq!(dirs[0].target, Some("target".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::INFO);
+        assert_eq!(dirs[0].in_span, Some("span-name".to_string()));
+    }
+
+    #[test]
+    fn parse_directives_with_special_characters_in_span_name() {
+        let span_name = "!\"#$%&'()*+-./:;<=>?@^_`|~[}";
+
+        let dirs = parse_directives(format!("target[{}]=info", span_name));
+        assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs);
+        assert_eq!(dirs[0].target, Some("target".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::INFO);
+        assert_eq!(dirs[0].in_span, Some(span_name.to_string()));
+    }
+
+    #[test]
+    fn parse_directives_with_invalid_span_chars() {
+        let invalid_span_name = "]{";
+
+        let dirs = parse_directives(format!("target[{}]=info", invalid_span_name));
+        assert_eq!(dirs.len(), 0, "\nparsed: {:#?}", dirs);
+    }
 }