diff --git a/Cargo.lock b/Cargo.lock index f1c5d818d7..20f71c802e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3418,6 +3418,7 @@ dependencies = [ "relay-event-normalization", "relay-filter", "relay-log", + "relay-pattern", "relay-pii", "relay-protocol", "relay-quotas", @@ -3522,6 +3523,7 @@ dependencies = [ "regex", "relay-common", "relay-event-schema", + "relay-pattern", "relay-protocol", "relay-ua", "serde", @@ -3675,6 +3677,7 @@ dependencies = [ "insta", "num-traits", "relay-common", + "relay-pattern", "relay-protocol-derive", "serde", "serde_json", diff --git a/relay-common/src/glob3.rs b/relay-common/src/glob3.rs deleted file mode 100644 index b7e53fe388..0000000000 --- a/relay-common/src/glob3.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Alternative implementation of serializable glob patterns. - -use std::fmt; -use std::sync::OnceLock; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use relay_pattern::Pattern; - -/// A list of patterns for glob matching. -#[derive(Clone, Default)] -pub struct GlobPatterns { - patterns: Vec, - compiled: OnceLock>, -} - -impl GlobPatterns { - /// Creates a new - pub fn new(patterns: Vec) -> Self { - Self { - patterns, - compiled: OnceLock::new(), - } - } - - /// Returns `true` if the list of patterns is empty. - pub fn is_empty(&self) -> bool { - // Check the list of patterns and not globs. Even if there are no globs to parse, we still - // want to serialize the "invalid" patterns to a downstream Relay. - self.patterns.is_empty() - } - - /// Returns `true` if any of the patterns match the given message. - pub fn is_match(&self, message: S) -> bool - where - S: AsRef, - { - let message = message.as_ref(); - if message.is_empty() { - return false; - } - - let compiled = self.compiled.get_or_init(|| { - self.patterns - .iter() - .filter_map(|p| Pattern::builder(p).case_insensitive(true).build().ok()) - .collect() - }); - - compiled.iter().any(|pattern| pattern.is_match(message)) - } -} - -impl fmt::Debug for GlobPatterns { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.patterns.fmt(f) - } -} - -impl Serialize for GlobPatterns { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.patterns.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for GlobPatterns { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let patterns = Deserialize::deserialize(deserializer)?; - Ok(GlobPatterns::new(patterns)) - } -} - -impl PartialEq for GlobPatterns { - fn eq(&self, other: &Self) -> bool { - self.patterns == other.patterns - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! globs { - ($($pattern:literal),*) => { - GlobPatterns::new(vec![ - $($pattern.to_string()),* - ]) - }; - } - - #[test] - fn test_match_empty() { - let globs = globs!(""); - assert!(!globs.is_match("foo")); - assert!(!globs.is_match("")); - } - - #[test] - fn test_match_literal() { - let globs = globs!("foo"); - assert!(globs.is_match("foo")); - } - - #[test] - fn test_match_negative() { - let globs = globs!("foo"); - assert!(!globs.is_match("nope")); - } - - #[test] - fn test_match_prefix() { - let globs = globs!("foo*"); - assert!(globs.is_match("foobarblub")); - } - - #[test] - fn test_match_suffix() { - let globs = globs!("*blub"); - assert!(globs.is_match("foobarblub")); - } - - #[test] - fn test_match_inner() { - let globs = globs!("*bar*"); - assert!(globs.is_match("foobarblub")); - } - - #[test] - fn test_match_utf8() {} - - #[test] - fn test_match_newline() { - let globs = globs!("*foo*"); - assert!(globs.is_match("foo\n")); - } - - #[test] - fn test_match_newline_inner() { - let globs = globs!("foo*bar"); - assert!(globs.is_match("foo\nbar")); - } - - #[test] - fn test_match_newline_pattern() { - let globs = globs!("foo*\n*bar"); - assert!(globs.is_match("foo \n bar")); - } - - #[test] - fn test_match_range() { - let globs = globs!("1.18.[0-4].*"); - assert!(globs.is_match("1.18.4.2153-2aa83397b")); - assert!(!globs.is_match("1.18.5.2153-2aa83397b")); - } - - #[test] - fn test_match_range_neg() { - let globs = globs!("1.18.[!0-4].*"); - assert!(!globs.is_match("1.18.4.2153-2aa83397b")); - assert!(globs.is_match("1.18.5.2153-2aa83397b")); - } - - #[test] - fn test_match_neg_unsupported() { - // this is not necessarily desirable behavior, but it is our current one: negation (!) - // outside of [] doesn't work - let globs = globs!("!1.18.4.*"); - assert!(!globs.is_match("1.18.4.2153-2aa83397b")); - assert!(!globs.is_match("1.18.5.2153-2aa83397b")); - } - - #[test] - fn test_match_escape_brace() { - let globs = globs!(r"/api/0/organizations/\{organization_slug\}/event*"); - assert!(globs.is_match("/api/0/organizations/{organization_slug}/event/foobar")); - assert!(!globs.is_match(r"/api/0/organizations/\{organization_slug\}/event/foobar")); - } -} diff --git a/relay-common/src/lib.rs b/relay-common/src/lib.rs index b28401064e..1eafb84f0b 100644 --- a/relay-common/src/lib.rs +++ b/relay-common/src/lib.rs @@ -9,7 +9,6 @@ mod macros; pub mod glob2; -pub mod glob3; pub mod time; pub use sentry_types::{Auth, Dsn, ParseAuthError, ParseDsnError, Scheme}; diff --git a/relay-dynamic-config/Cargo.toml b/relay-dynamic-config/Cargo.toml index 06fbf0a493..1549b09d66 100644 --- a/relay-dynamic-config/Cargo.toml +++ b/relay-dynamic-config/Cargo.toml @@ -24,6 +24,7 @@ relay-common = { workspace = true } relay-event-normalization = { workspace = true } relay-filter = { workspace = true } relay-log = { workspace = true } +relay-pattern= { workspace = true } relay-pii = { workspace = true } relay-protocol = { workspace = true } relay-quotas = { workspace = true } diff --git a/relay-dynamic-config/src/metrics.rs b/relay-dynamic-config/src/metrics.rs index 12598f9ec8..324085ef90 100644 --- a/relay-dynamic-config/src/metrics.rs +++ b/relay-dynamic-config/src/metrics.rs @@ -8,8 +8,8 @@ use std::str::FromStr; use relay_base_schema::data_category::DataCategory; use relay_cardinality::CardinalityLimit; use relay_common::glob2::LazyGlob; -use relay_common::glob3::GlobPatterns; use relay_common::impl_str_serde; +use relay_pattern::{Patterns, TypedPatterns}; use relay_protocol::RuleCondition; use serde::{Deserialize, Serialize}; @@ -23,8 +23,8 @@ pub struct Metrics { #[serde(skip_serializing_if = "Vec::is_empty")] pub cardinality_limits: Vec, /// List of patterns for blocking metrics based on their name. - #[serde(skip_serializing_if = "GlobPatterns::is_empty")] - pub denied_names: GlobPatterns, + #[serde(skip_serializing_if = "Patterns::is_empty")] + pub denied_names: TypedPatterns, /// Configuration for removing tags from a bucket. /// /// Note that removing tags does not drop the overall metric bucket. @@ -43,11 +43,14 @@ impl Metrics { /// Configuration for removing tags matching the `tag` pattern on metrics whose name matches the `name` pattern. #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] +#[serde(default)] pub struct TagBlock { /// Name of metric of which we want to remove certain tags. - pub name: GlobPatterns, + #[serde(skip_serializing_if = "Patterns::is_empty")] + pub name: TypedPatterns, /// Pattern to match keys of tags that we want to remove. - pub tags: GlobPatterns, + #[serde(skip_serializing_if = "Patterns::is_empty")] + pub tags: TypedPatterns, } /// Rule defining when a target tag should be set on a metric. diff --git a/relay-filter/Cargo.toml b/relay-filter/Cargo.toml index 20cdcb081a..e61b9c6a24 100644 --- a/relay-filter/Cargo.toml +++ b/relay-filter/Cargo.toml @@ -18,6 +18,7 @@ once_cell = { workspace = true } indexmap = { workspace = true } regex = { workspace = true } relay-common = { workspace = true } +relay-pattern = { workspace = true } relay-event-schema = { workspace = true } relay-protocol = { workspace = true } relay-ua = { workspace = true } diff --git a/relay-filter/src/config.rs b/relay-filter/src/config.rs index 281a3eb9f5..d11b8908ea 100644 --- a/relay-filter/src/config.rs +++ b/relay-filter/src/config.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use std::str::FromStr; use indexmap::IndexMap; -use relay_common::glob3::GlobPatterns; +use relay_pattern::{CaseInsensitive, TypedPatterns}; use relay_protocol::RuleCondition; use serde::ser::SerializeSeq; use serde::{de, Deserialize, Serialize, Serializer}; @@ -173,7 +173,7 @@ impl CspFilterConfig { #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ErrorMessagesFilterConfig { /// List of error message patterns that will be filtered. - pub patterns: GlobPatterns, + pub patterns: TypedPatterns, } /// Configuration for transaction name filter. @@ -181,7 +181,7 @@ pub struct ErrorMessagesFilterConfig { #[serde(rename_all = "camelCase")] pub struct IgnoreTransactionsFilterConfig { /// List of patterns for ignored transactions that should be filtered. - pub patterns: GlobPatterns, + pub patterns: TypedPatterns, /// True if the filter is enabled #[serde(default)] pub is_enabled: bool, @@ -205,7 +205,7 @@ impl ErrorMessagesFilterConfig { #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ReleasesFilterConfig { /// List of release names that will be filtered. - pub releases: GlobPatterns, + pub releases: TypedPatterns, } impl ReleasesFilterConfig { @@ -632,7 +632,7 @@ mod tests { disallowed_sources: vec!["https://*".to_string()], }, error_messages: ErrorMessagesFilterConfig { - patterns: GlobPatterns::new(vec!["Panic".to_string()]), + patterns: TypedPatterns::from(["Panic".to_owned()]), }, legacy_browsers: LegacyBrowsersFilterConfig { is_enabled: false, @@ -643,16 +643,16 @@ mod tests { }, localhost: FilterConfig { is_enabled: true }, releases: ReleasesFilterConfig { - releases: GlobPatterns::new(vec!["1.2.3".to_string()]), + releases: TypedPatterns::from(["1.2.3".to_owned()]), }, ignore_transactions: IgnoreTransactionsFilterConfig { - patterns: GlobPatterns::new(vec!["*health*".to_string()]), + patterns: TypedPatterns::from(["*health*".to_owned()]), is_enabled: true, }, generic: GenericFiltersConfig { version: 1, filters: vec![GenericFilterConfig { - id: "hydrationError".to_string(), + id: "hydrationError".to_owned(), is_enabled: true, condition: Some(RuleCondition::eq("event.exceptions", "HydrationError")), }] diff --git a/relay-filter/src/error_messages.rs b/relay-filter/src/error_messages.rs index 579897f46d..70defad3a2 100644 --- a/relay-filter/src/error_messages.rs +++ b/relay-filter/src/error_messages.rs @@ -5,12 +5,12 @@ use std::borrow::Cow; -use relay_common::glob3::GlobPatterns; +use relay_pattern::Patterns; use crate::{ErrorMessagesFilterConfig, FilterStatKey, Filterable}; /// Checks events by patterns in their error messages. -fn matches(item: &F, patterns: &GlobPatterns) -> bool { +fn matches(item: &F, patterns: &Patterns) -> bool { if let Some(logentry) = item.logentry() { if let Some(message) = logentry.formatted.value() { if patterns.is_match(message.as_ref()) { @@ -59,6 +59,7 @@ pub fn should_filter( #[cfg(test)] mod tests { use relay_event_schema::protocol::{Event, Exception, LogEntry, Values}; + use relay_pattern::TypedPatterns; use relay_protocol::Annotated; use super::*; @@ -68,19 +69,19 @@ mod tests { let configs = &[ // with globs ErrorMessagesFilterConfig { - patterns: GlobPatterns::new(vec![ - "filteredexception*".to_string(), - "*this is a filtered exception.".to_string(), - "".to_string(), - "this is".to_string(), + patterns: TypedPatterns::from([ + "filteredexception*".to_owned(), + "*this is a filtered exception.".to_owned(), + "".to_owned(), + "this is".to_owned(), ]), }, // without globs ErrorMessagesFilterConfig { - patterns: GlobPatterns::new(vec![ - "filteredexception: this is a filtered exception.".to_string(), - "filteredexception".to_string(), - "this is a filtered exception.".to_string(), + patterns: TypedPatterns::from([ + "filteredexception: this is a filtered exception.".to_owned(), + "filteredexception".to_owned(), + "this is a filtered exception.".to_owned(), ]), }, ]; @@ -173,7 +174,7 @@ mod tests { let pattern = "*https://reactjs.org/docs/error-decoder.html?invariant={418,419,422,423,425}*"; let config = ErrorMessagesFilterConfig { - patterns: GlobPatterns::new(vec![pattern.to_string()]), + patterns: TypedPatterns::from([pattern.to_owned()]), }; let event = Annotated::::from_json( @@ -201,7 +202,7 @@ mod tests { ]; let config = ErrorMessagesFilterConfig { - patterns: GlobPatterns::new(vec![ + patterns: TypedPatterns::from([ "ChunkLoadError: Loading chunk *".to_owned(), "*Uncaught *: ChunkLoadError: Loading chunk *".to_owned(), ]), diff --git a/relay-filter/src/releases.rs b/relay-filter/src/releases.rs index 6d1e7e4836..f43dd80b35 100644 --- a/relay-filter/src/releases.rs +++ b/relay-filter/src/releases.rs @@ -22,7 +22,6 @@ where #[cfg(test)] mod tests { - use relay_common::glob3::GlobPatterns; use relay_event_schema::protocol::{Event, LenientString, Span, SpanData}; use relay_protocol::Annotated; @@ -73,9 +72,7 @@ mod tests { let span = get_span_for_release(release); let config = ReleasesFilterConfig { - releases: GlobPatterns::new( - blocked_releases.iter().map(|&r| r.to_string()).collect(), - ), + releases: blocked_releases.iter().map(|&r| r.to_owned()).collect(), }; let actual = should_filter(&event, &config) != Ok(()); diff --git a/relay-filter/src/transaction_name.rs b/relay-filter/src/transaction_name.rs index d60a9e10ed..e39732acba 100644 --- a/relay-filter/src/transaction_name.rs +++ b/relay-filter/src/transaction_name.rs @@ -2,11 +2,11 @@ //! //! If this filter is enabled transactions from healthcheck endpoints will be filtered out. -use relay_common::glob3::GlobPatterns; +use relay_pattern::Patterns; use crate::{FilterStatKey, Filterable, IgnoreTransactionsFilterConfig}; -fn matches(transaction: Option<&str>, patterns: &GlobPatterns) -> bool { +fn matches(transaction: Option<&str>, patterns: &Patterns) -> bool { transaction.map_or(false, |transaction| patterns.is_match(transaction)) } @@ -29,6 +29,7 @@ pub fn should_filter( #[cfg(test)] mod tests { use relay_event_schema::protocol::{Event, EventType}; + use relay_pattern::TypedPatterns; use relay_protocol::Annotated; use super::*; @@ -55,7 +56,7 @@ mod tests { .to_vec(); IgnoreTransactionsFilterConfig { - patterns: GlobPatterns::new(patterns_raw), + patterns: TypedPatterns::from(patterns_raw), is_enabled: true, } } @@ -180,7 +181,7 @@ mod tests { let filter_result = should_filter( &event, &IgnoreTransactionsFilterConfig { - patterns: GlobPatterns::new(vec![]), + patterns: TypedPatterns::default(), is_enabled: true, }, ); diff --git a/relay-pattern/src/lib.rs b/relay-pattern/src/lib.rs index 51a9dab4c8..fcbef6d6d5 100644 --- a/relay-pattern/src/lib.rs +++ b/relay-pattern/src/lib.rs @@ -167,6 +167,13 @@ impl Patterns { .iter() .any(|s| s.is_match(haystack, self.options)) } + + /// Returns `true` if this instance contains no patterns. + /// + /// An empty [`Patterns`] never matches any input. + pub fn is_empty(&self) -> bool { + self.strategies.is_empty() + } } /// A builder for a [`Pattern`]. diff --git a/relay-pattern/src/typed.rs b/relay-pattern/src/typed.rs index 56835132d6..64dd73a722 100644 --- a/relay-pattern/src/typed.rs +++ b/relay-pattern/src/typed.rs @@ -1,3 +1,5 @@ +use core::fmt; +use std::fmt::Debug; use std::marker::PhantomData; use std::ops::Deref; @@ -48,6 +50,7 @@ impl PatternConfig for CaseInsensitive { /// let pattern = MetricPattern::new("[cd]:foo/bar").unwrap(); /// assert!(pattern.is_match("c:foo/bar")); /// ``` +#[derive(Debug)] pub struct TypedPattern { pattern: Pattern, _phantom: PhantomData, @@ -122,7 +125,6 @@ impl Deref for TypedPattern { /// [`Patterns`] with a compile time configured [`PatternConfig`]. pub struct TypedPatterns { patterns: Patterns, - #[cfg(feature = "serde")] raw: Vec, _phantom: PhantomData, } @@ -141,6 +143,85 @@ impl TypedPatterns { } } +impl Default for TypedPatterns { + fn default() -> Self { + Self::builder().build() + } +} + +impl PartialEq for TypedPatterns { + fn eq(&self, other: &Self) -> bool { + self.raw.eq(&other.raw) + } +} + +impl From for TypedPatterns { + fn from(value: String) -> Self { + [value].into_iter().collect() + } +} + +impl From> for TypedPatterns { + fn from(value: Vec) -> Self { + value.into_iter().collect() + } +} + +impl From<[String; N]> for TypedPatterns { + fn from(value: [String; N]) -> Self { + value.into_iter().collect() + } +} + +/// Creates [`Patterns`] from an iterator of strings. +/// +/// Invalid patterns are ignored. +impl FromIterator for TypedPatterns { + fn from_iter>(iter: T) -> Self { + let mut builder = Self::builder(); + for pattern in iter.into_iter() { + let _ = builder.add(pattern); + } + builder.build() + } +} + +impl From> for Patterns { + fn from(value: TypedPatterns) -> Self { + value.patterns + } +} + +impl AsRef for TypedPatterns { + fn as_ref(&self) -> &Patterns { + &self.patterns + } +} + +impl Deref for TypedPatterns { + type Target = Patterns; + + fn deref(&self) -> &Self::Target { + &self.patterns + } +} + +impl Clone for TypedPatterns { + fn clone(&self) -> Self { + Self { + patterns: self.patterns.clone(), + raw: self.raw.clone(), + _phantom: PhantomData, + } + } +} + +impl fmt::Debug for TypedPatterns { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.raw.fmt(f) + } +} + /// Deserializes patterns from a sequence of strings. /// /// Invalid patterns are ignored while deserializing. @@ -188,29 +269,8 @@ impl serde::Serialize for TypedPatterns { } } -impl From> for Patterns { - fn from(value: TypedPatterns) -> Self { - value.patterns - } -} - -impl AsRef for TypedPatterns { - fn as_ref(&self) -> &Patterns { - &self.patterns - } -} - -impl Deref for TypedPatterns { - type Target = Patterns; - - fn deref(&self) -> &Self::Target { - &self.patterns - } -} - pub struct TypedPatternsBuilder { builder: PatternsBuilderConfigured, - #[cfg(feature = "serde")] raw: Vec, _phantom: PhantomData, } @@ -219,7 +279,6 @@ impl TypedPatternsBuilder { /// Adds a pattern to the builder. pub fn add(&mut self, pattern: String) -> Result<&mut Self, Error> { self.builder.add(&pattern)?; - #[cfg(feature = "serde")] self.raw.push(pattern); Ok(self) } @@ -228,7 +287,6 @@ impl TypedPatternsBuilder { pub fn build(self) -> TypedPatterns { TypedPatterns { patterns: self.builder.build(), - #[cfg(feature = "serde")] raw: self.raw, _phantom: PhantomData, } @@ -238,7 +296,6 @@ impl TypedPatternsBuilder { pub fn take(&mut self) -> TypedPatterns { TypedPatterns { patterns: self.builder.take(), - #[cfg(feature = "serde")] raw: std::mem::take(&mut self.raw), _phantom: PhantomData, } diff --git a/relay-protocol/Cargo.toml b/relay-protocol/Cargo.toml index 948be0bf7f..c231e19148 100644 --- a/relay-protocol/Cargo.toml +++ b/relay-protocol/Cargo.toml @@ -15,12 +15,13 @@ workspace = true [dependencies] num-traits = { workspace = true } relay-common = { workspace = true } +relay-pattern = { workspace = true } relay-protocol-derive = { workspace = true, optional = true } serde = { workspace = true } serde_json = { workspace = true } smallvec = { workspace = true } -uuid = { workspace = true } unicase = { workspace = true } +uuid = { workspace = true } [dev-dependencies] insta = { workspace = true } diff --git a/relay-protocol/src/condition.rs b/relay-protocol/src/condition.rs index 4d8d40e893..19887a3166 100644 --- a/relay-protocol/src/condition.rs +++ b/relay-protocol/src/condition.rs @@ -2,7 +2,7 @@ //! //! The root type is [`RuleCondition`]. -use relay_common::glob3::GlobPatterns; +use relay_pattern::{CaseInsensitive, TypedPatterns}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -163,7 +163,7 @@ pub struct GlobCondition { /// A list of glob patterns to check. /// /// Note that this cannot be a single value, it must be a list of values. - pub value: GlobPatterns, + pub value: TypedPatterns, } impl GlobCondition { @@ -171,7 +171,7 @@ impl GlobCondition { pub fn new(field: impl Into, value: impl IntoStrings) -> Self { Self { name: field.into(), - value: GlobPatterns::new(value.into_strings()), + value: TypedPatterns::from(value.into_strings()), } } diff --git a/relay-server/src/services/processor/metrics.rs b/relay-server/src/services/processor/metrics.rs index a194d4cbe1..8c6ac4fcc4 100644 --- a/relay-server/src/services/processor/metrics.rs +++ b/relay-server/src/services/processor/metrics.rs @@ -44,7 +44,7 @@ pub fn apply_project_info( }; if let ErrorBoundary::Ok(ref metric_config) = project_info.config.metrics { - if metric_config.denied_names.is_match(&*bucket.name) { + if metric_config.denied_names.is_match(&bucket.name) { relay_log::trace!(mri = &*bucket.name, "dropping metrics due to block list"); denied_buckets.push(bucket); return None; @@ -91,7 +91,7 @@ fn is_metric_namespace_valid(state: &ProjectInfo, namespace: MetricNamespace) -> /// Removes tags based on user configured deny list. fn remove_matching_bucket_tags(metric_config: &Metrics, bucket: &mut Bucket) { for tag_block in &metric_config.denied_tags { - if tag_block.name.is_match(&*bucket.name) { + if tag_block.name.is_match(&bucket.name) { bucket .tags .retain(|tag_key, _| !tag_block.tags.is_match(tag_key)); @@ -104,7 +104,6 @@ mod tests { use std::collections::BTreeMap; use relay_base_schema::project::{ProjectId, ProjectKey}; - use relay_common::glob3::GlobPatterns; use relay_dynamic_config::TagBlock; use relay_metrics::{BucketValue, UnixTimestamp}; use relay_system::Addr; @@ -141,9 +140,9 @@ mod tests { #[test] fn test_remove_tags() { let mut tags = BTreeMap::default(); - tags.insert("foobazbar".to_string(), "val".to_string()); - tags.insert("foobaz".to_string(), "val".to_string()); - tags.insert("bazbar".to_string(), "val".to_string()); + tags.insert("foobazbar".to_owned(), "val".to_owned()); + tags.insert("foobaz".to_owned(), "val".to_owned()); + tags.insert("bazbar".to_owned(), "val".to_owned()); let mut bucket = get_test_bucket("foobar", tags); @@ -151,8 +150,8 @@ mod tests { let metric_config = Metrics { denied_tags: vec![TagBlock { - name: GlobPatterns::new(vec!["foobar".to_string()]), - tags: GlobPatterns::new(vec![tag_block_pattern.to_string()]), + name: "foobar".to_owned().into(), + tags: tag_block_pattern.to_owned().into(), }], ..Default::default() };