datadog-statsd-schema 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.envrc +2 -0
- data/.rspec +2 -1
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +32 -47
- data/FUTURE_DIRECTION.md +32 -0
- data/README.md +309 -258
- data/Rakefile +7 -7
- data/examples/schema/example_marathon.rb +29 -0
- data/examples/shared.rb +1 -1
- data/exe/dss +8 -0
- data/lib/datadog/statsd/emitter.rb +102 -21
- data/lib/datadog/statsd/schema/analyzer.rb +397 -0
- data/lib/datadog/statsd/schema/cli.rb +16 -0
- data/lib/datadog/statsd/schema/commands/analyze.rb +52 -0
- data/lib/datadog/statsd/schema/commands.rb +14 -0
- data/lib/datadog/statsd/schema/errors.rb +54 -1
- data/lib/datadog/statsd/schema/metric_definition.rb +86 -3
- data/lib/datadog/statsd/schema/namespace.rb +91 -5
- data/lib/datadog/statsd/schema/schema_builder.rb +162 -4
- data/lib/datadog/statsd/schema/tag_definition.rb +66 -6
- data/lib/datadog/statsd/schema/version.rb +6 -1
- data/lib/datadog/statsd/schema.rb +91 -13
- metadata +25 -4
- data/exe/datadog-statsd-schema +0 -3
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/cli"
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
class Statsd
|
7
|
+
module Schema
|
8
|
+
module Commands
|
9
|
+
# @description Analyze a schema file for metrics and validation
|
10
|
+
class Analyze < Dry::CLI::Command
|
11
|
+
class << self
|
12
|
+
attr_accessor :stdout, :stderr
|
13
|
+
end
|
14
|
+
|
15
|
+
self.stdout = $stdout
|
16
|
+
self.stderr = $stderr
|
17
|
+
|
18
|
+
desc "Analyze a schema file for metrics and validation"
|
19
|
+
|
20
|
+
option :file, aliases: %w[-f], type: :string, required: true, desc: "Path to the schema file to analyze"
|
21
|
+
option :color, aliases: %w[-c], type: :boolean, required: false, desc: "Enable/Disable color output"
|
22
|
+
|
23
|
+
# @description Analyze a schema file for metrics and validation
|
24
|
+
# @param options [Hash] The options for the command
|
25
|
+
# @option options [String] :file The path to the schema file to analyze
|
26
|
+
# @option options [Boolean] :color Enable/Disable color output
|
27
|
+
# @return [void]
|
28
|
+
def call(**options)
|
29
|
+
file = options[:file]
|
30
|
+
|
31
|
+
unless file
|
32
|
+
warn "Error: --file option is required"
|
33
|
+
warn "Usage: dss analyze --file <schema.rb>"
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
37
|
+
warn "Analyzing schema file: #{file}, color: #{options[:color]}"
|
38
|
+
@schema = ::Datadog::Statsd::Schema.load_file(file)
|
39
|
+
::Datadog::Statsd::Schema::Analyzer.new([@schema],
|
40
|
+
stdout: self.class.stdout,
|
41
|
+
stderr: self.class.stderr,
|
42
|
+
color: options[:color]).analyze
|
43
|
+
end
|
44
|
+
|
45
|
+
def warn(message)
|
46
|
+
self.class.stderr.puts message
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -3,12 +3,35 @@
|
|
3
3
|
require "colored2"
|
4
4
|
require "active_support/core_ext/string/inflections"
|
5
5
|
|
6
|
+
# @author Datadog Team
|
7
|
+
# @since 0.1.0
|
6
8
|
module Datadog
|
7
9
|
class Statsd
|
10
|
+
# Schema definition and validation module for StatsD metrics
|
8
11
|
module Schema
|
12
|
+
# Base error class for all schema validation errors
|
13
|
+
# Provides context about where the error occurred including namespace, metric, and tag information
|
14
|
+
# @abstract Base class for schema validation errors
|
15
|
+
# @author Datadog Team
|
16
|
+
# @since 0.1.0
|
9
17
|
class SchemaError < StandardError
|
10
|
-
|
18
|
+
# The namespace where the error occurred
|
19
|
+
# @return [String] Namespace path or placeholder if not available
|
20
|
+
attr_reader :namespace
|
11
21
|
|
22
|
+
# The metric name where the error occurred
|
23
|
+
# @return [String] Metric name or placeholder if not available
|
24
|
+
attr_reader :metric
|
25
|
+
|
26
|
+
# The tag name where the error occurred
|
27
|
+
# @return [String] Tag name or placeholder if not available
|
28
|
+
attr_reader :tag
|
29
|
+
|
30
|
+
# Initialize a new schema error with context information
|
31
|
+
# @param message [String, nil] Custom error message, will be auto-generated if nil
|
32
|
+
# @param namespace [String] Namespace context for the error
|
33
|
+
# @param metric [String] Metric context for the error
|
34
|
+
# @param tag [String] Tag context for the error
|
12
35
|
def initialize(message = nil, namespace: "<-no-namespace->", metric: "<-no-metric->", tag: "<-no-tag->")
|
13
36
|
@namespace = namespace
|
14
37
|
@metric = metric
|
@@ -19,16 +42,46 @@ module Datadog
|
|
19
42
|
end
|
20
43
|
end
|
21
44
|
|
45
|
+
# Raised when a metric is used that doesn't exist in the schema
|
46
|
+
# @example
|
47
|
+
# # This would raise UnknownMetricError if 'unknown_metric' is not defined in the schema
|
48
|
+
# emitter.increment('unknown_metric')
|
22
49
|
class UnknownMetricError < SchemaError; end
|
23
50
|
|
51
|
+
# Raised when a tag is used that doesn't exist in the schema or is not allowed for the metric
|
52
|
+
# @example
|
53
|
+
# # This would raise InvalidTagError if 'invalid_tag' is not allowed for the metric
|
54
|
+
# emitter.increment('valid_metric', tags: { invalid_tag: 'value' })
|
24
55
|
class InvalidTagError < SchemaError; end
|
25
56
|
|
57
|
+
# Raised when a required tag is missing from a metric call
|
58
|
+
# @example
|
59
|
+
# # This would raise MissingRequiredTagError if 'environment' tag is required
|
60
|
+
# emitter.increment('metric_requiring_env_tag', tags: { service: 'web' })
|
26
61
|
class MissingRequiredTagError < SchemaError; end
|
27
62
|
|
63
|
+
# Raised when a metric is called with the wrong type
|
64
|
+
# @example
|
65
|
+
# # This would raise InvalidMetricTypeError if 'response_time' is defined as a histogram
|
66
|
+
# emitter.increment('response_time') # Should be emitter.histogram('response_time')
|
28
67
|
class InvalidMetricTypeError < SchemaError; end
|
29
68
|
|
69
|
+
# Raised when attempting to define a metric that already exists in the schema
|
70
|
+
# @example Schema definition error
|
71
|
+
# namespace :web do
|
72
|
+
# metrics do
|
73
|
+
# counter :requests
|
74
|
+
# counter :requests # This would raise DuplicateMetricError
|
75
|
+
# end
|
76
|
+
# end
|
30
77
|
class DuplicateMetricError < SchemaError; end
|
31
78
|
|
79
|
+
# Raised when a namespace definition is invalid
|
80
|
+
# @example
|
81
|
+
# # This might be raised for namespace naming conflicts or invalid structure
|
82
|
+
# namespace :invalid_namespace do
|
83
|
+
# # ... invalid configuration
|
84
|
+
# end
|
32
85
|
class InvalidNamespaceError < SchemaError; end
|
33
86
|
end
|
34
87
|
end
|
@@ -3,28 +3,78 @@
|
|
3
3
|
require "dry-struct"
|
4
4
|
require "dry-types"
|
5
5
|
|
6
|
+
# @author Datadog Team
|
7
|
+
# @since 0.1.0
|
6
8
|
module Datadog
|
7
9
|
class Statsd
|
10
|
+
# Schema definition and validation module for StatsD metrics
|
8
11
|
module Schema
|
12
|
+
# Represents a metric definition within a schema namespace
|
13
|
+
# Defines the metric type, allowed/required tags, validation rules, and metadata
|
14
|
+
# @example Basic metric definition
|
15
|
+
# metric_def = MetricDefinition.new(
|
16
|
+
# name: :page_views,
|
17
|
+
# type: :counter,
|
18
|
+
# allowed_tags: [:controller, :action],
|
19
|
+
# required_tags: [:controller]
|
20
|
+
# )
|
21
|
+
# @example Metric with description and units
|
22
|
+
# metric_def = MetricDefinition.new(
|
23
|
+
# name: :request_duration,
|
24
|
+
# type: :distribution,
|
25
|
+
# description: "HTTP request processing time",
|
26
|
+
# units: "milliseconds",
|
27
|
+
# allowed_tags: [:controller, :action, :status_code],
|
28
|
+
# required_tags: [:controller, :action]
|
29
|
+
# )
|
30
|
+
# @author Datadog Team
|
31
|
+
# @since 0.1.0
|
9
32
|
class MetricDefinition < Dry::Struct
|
10
|
-
# Include the types module for easier access
|
33
|
+
# Include the types module for easier access to Dry::Types
|
11
34
|
module Types
|
12
35
|
include Dry.Types()
|
13
36
|
end
|
14
37
|
|
15
|
-
# Valid metric types
|
38
|
+
# Valid metric types supported by StatsD
|
16
39
|
VALID_METRIC_TYPES = %i[counter gauge histogram distribution timing set].freeze
|
17
40
|
|
41
|
+
# The metric name as a symbol
|
42
|
+
# @return [Symbol] Metric name
|
18
43
|
attribute :name, Types::Strict::Symbol
|
44
|
+
|
45
|
+
# The metric type (counter, gauge, histogram, distribution, timing, set)
|
46
|
+
# @return [Symbol] One of the valid metric types
|
19
47
|
attribute :type, Types::Strict::Symbol.constrained(included_in: VALID_METRIC_TYPES)
|
48
|
+
|
49
|
+
# Human-readable description of what this metric measures
|
50
|
+
# @return [String, nil] Description text
|
20
51
|
attribute :description, Types::String.optional.default(nil)
|
52
|
+
|
53
|
+
# Array of tag names that are allowed for this metric
|
54
|
+
# @return [Array<Symbol>] Allowed tag names (empty array means all tags allowed)
|
21
55
|
attribute :allowed_tags, Types::Array.of(Types::Symbol).default([].freeze)
|
56
|
+
|
57
|
+
# Array of tag names that are required for this metric
|
58
|
+
# @return [Array<Symbol>] Required tag names
|
22
59
|
attribute :required_tags, Types::Array.of(Types::Symbol).default([].freeze)
|
60
|
+
|
61
|
+
# Path to another metric to inherit tags from
|
62
|
+
# @return [String, nil] Dot-separated path to parent metric
|
23
63
|
attribute :inherit_tags, Types::String.optional.default(nil)
|
64
|
+
|
65
|
+
# Units of measurement for this metric (e.g., "milliseconds", "bytes")
|
66
|
+
# @return [String, nil] Unit description
|
24
67
|
attribute :units, Types::String.optional.default(nil)
|
68
|
+
|
69
|
+
# The namespace this metric belongs to
|
70
|
+
# @return [Symbol, nil] Namespace name
|
25
71
|
attribute :namespace, Types::Strict::Symbol.optional.default(nil)
|
26
72
|
|
27
73
|
# Get the full metric name including namespace path
|
74
|
+
# @param namespace_path [Array<Symbol>] Array of namespace names leading to this metric
|
75
|
+
# @return [String] Fully qualified metric name
|
76
|
+
# @example
|
77
|
+
# metric_def.full_name([:web, :api]) # => "web.api.page_views"
|
28
78
|
def full_name(namespace_path = [])
|
29
79
|
return name.to_s if namespace_path.empty?
|
30
80
|
|
@@ -32,24 +82,44 @@ module Datadog
|
|
32
82
|
end
|
33
83
|
|
34
84
|
# Check if a tag is allowed for this metric
|
85
|
+
# @param tag_name [String, Symbol] Tag name to check
|
86
|
+
# @return [Boolean] true if tag is allowed (or no restrictions exist)
|
87
|
+
# @example
|
88
|
+
# metric_def.allows_tag?(:controller) # => true
|
89
|
+
# metric_def.allows_tag?(:invalid_tag) # => false (if restrictions exist)
|
35
90
|
def allows_tag?(tag_name)
|
36
91
|
tag_symbol = tag_name.to_sym
|
37
92
|
allowed_tags.empty? || allowed_tags.include?(tag_symbol)
|
38
93
|
end
|
39
94
|
|
40
95
|
# Check if a tag is required for this metric
|
96
|
+
# @param tag_name [String, Symbol] Tag name to check
|
97
|
+
# @return [Boolean] true if tag is required
|
98
|
+
# @example
|
99
|
+
# metric_def.requires_tag?(:controller) # => true
|
100
|
+
# metric_def.requires_tag?(:optional_tag) # => false
|
41
101
|
def requires_tag?(tag_name)
|
42
102
|
tag_symbol = tag_name.to_sym
|
43
103
|
required_tags.include?(tag_symbol)
|
44
104
|
end
|
45
105
|
|
46
106
|
# Get all missing required tags from a provided tag set
|
107
|
+
# @param provided_tags [Hash] Hash of tag names to values
|
108
|
+
# @return [Array<Symbol>] Array of missing required tag names
|
109
|
+
# @example
|
110
|
+
# metric_def.missing_required_tags(controller: "users")
|
111
|
+
# # => [:action] (if action is also required)
|
47
112
|
def missing_required_tags(provided_tags)
|
48
113
|
provided_tag_symbols = provided_tags.keys.map(&:to_sym)
|
49
114
|
required_tags - provided_tag_symbols
|
50
115
|
end
|
51
116
|
|
52
117
|
# Get all invalid tags from a provided tag set
|
118
|
+
# @param provided_tags [Hash] Hash of tag names to values
|
119
|
+
# @return [Array<Symbol>] Array of invalid tag names
|
120
|
+
# @example
|
121
|
+
# metric_def.invalid_tags(controller: "users", invalid: "value")
|
122
|
+
# # => [:invalid] (if only controller is allowed)
|
53
123
|
def invalid_tags(provided_tags)
|
54
124
|
return [] if allowed_tags.empty? # No restrictions
|
55
125
|
|
@@ -58,31 +128,41 @@ module Datadog
|
|
58
128
|
end
|
59
129
|
|
60
130
|
# Validate a complete tag set for this metric
|
131
|
+
# @param provided_tags [Hash] Hash of tag names to values
|
132
|
+
# @return [Boolean] true if all tags are valid
|
133
|
+
# @example
|
134
|
+
# metric_def.valid_tags?(controller: "users", action: "show") # => true
|
61
135
|
def valid_tags?(provided_tags)
|
62
136
|
missing_required_tags(provided_tags).empty? && invalid_tags(provided_tags).empty?
|
63
137
|
end
|
64
138
|
|
65
139
|
# Check if this is a timing-based metric
|
140
|
+
# @return [Boolean] true for timing, distribution, or histogram metrics
|
66
141
|
def timing_metric?
|
67
142
|
%i[timing distribution histogram].include?(type)
|
68
143
|
end
|
69
144
|
|
70
145
|
# Check if this is a counting metric
|
146
|
+
# @return [Boolean] true for counter metrics
|
71
147
|
def counting_metric?
|
72
148
|
%i[counter].include?(type)
|
73
149
|
end
|
74
150
|
|
75
151
|
# Check if this is a gauge metric
|
152
|
+
# @return [Boolean] true for gauge metrics
|
76
153
|
def gauge_metric?
|
77
154
|
type == :gauge
|
78
155
|
end
|
79
156
|
|
80
157
|
# Check if this is a set metric
|
158
|
+
# @return [Boolean] true for set metrics
|
81
159
|
def set_metric?
|
82
160
|
type == :set
|
83
161
|
end
|
84
162
|
|
85
|
-
# Get effective tags by merging with inherited tags if present
|
163
|
+
# Get effective allowed tags by merging with inherited tags if present
|
164
|
+
# @param schema_registry [Object] Registry to look up inherited metrics
|
165
|
+
# @return [Array<Symbol>] Combined allowed tags including inherited ones
|
86
166
|
def effective_allowed_tags(schema_registry = nil)
|
87
167
|
return allowed_tags unless inherit_tags && schema_registry
|
88
168
|
|
@@ -92,6 +172,9 @@ module Datadog
|
|
92
172
|
(inherited_metric.effective_allowed_tags(schema_registry) + allowed_tags).uniq
|
93
173
|
end
|
94
174
|
|
175
|
+
# Get effective required tags by merging with inherited tags if present
|
176
|
+
# @param schema_registry [Object] Registry to look up inherited metrics
|
177
|
+
# @return [Array<Symbol>] Combined required tags including inherited ones
|
95
178
|
def effective_required_tags(schema_registry = nil)
|
96
179
|
return required_tags unless inherit_tags && schema_registry
|
97
180
|
|
@@ -5,22 +5,58 @@ require "dry-types"
|
|
5
5
|
require_relative "tag_definition"
|
6
6
|
require_relative "metric_definition"
|
7
7
|
|
8
|
+
# @author Datadog Team
|
9
|
+
# @since 0.1.0
|
8
10
|
module Datadog
|
9
11
|
class Statsd
|
12
|
+
# Schema definition and validation module for StatsD metrics
|
10
13
|
module Schema
|
14
|
+
# Represents a namespace in the metric schema hierarchy
|
15
|
+
# Namespaces contain tags, metrics, and nested namespaces, providing organization and scoping
|
16
|
+
# @example Basic namespace
|
17
|
+
# namespace = Namespace.new(
|
18
|
+
# name: :web,
|
19
|
+
# description: "Web application metrics"
|
20
|
+
# )
|
21
|
+
# @example Namespace with tags and metrics
|
22
|
+
# namespace = Namespace.new(
|
23
|
+
# name: :api,
|
24
|
+
# tags: { controller: tag_def, action: tag_def2 },
|
25
|
+
# metrics: { requests: metric_def }
|
26
|
+
# )
|
27
|
+
# @author Datadog Team
|
28
|
+
# @since 0.1.0
|
11
29
|
class Namespace < Dry::Struct
|
12
|
-
# Include the types module for easier access
|
30
|
+
# Include the types module for easier access to Dry::Typesa
|
13
31
|
module Types
|
14
32
|
include Dry.Types()
|
15
33
|
end
|
16
34
|
|
35
|
+
# The namespace name as a symbol
|
36
|
+
# @return [Symbol] Namespace name
|
17
37
|
attribute :name, Types::Strict::Symbol
|
38
|
+
|
39
|
+
# Hash of tag definitions within this namespace
|
40
|
+
# @return [Hash<Symbol, TagDefinition>] Tag name to TagDefinition mapping
|
18
41
|
attribute :tags, Types::Hash.map(Types::Symbol, TagDefinition).default({}.freeze)
|
42
|
+
|
43
|
+
# Hash of metric definitions within this namespace
|
44
|
+
# @return [Hash<Symbol, MetricDefinition>] Metric name to MetricDefinition mapping
|
19
45
|
attribute :metrics, Types::Hash.map(Types::Symbol, MetricDefinition).default({}.freeze)
|
46
|
+
|
47
|
+
# Hash of nested namespaces within this namespace
|
48
|
+
# @return [Hash<Symbol, Namespace>] Namespace name to Namespace mapping
|
20
49
|
attribute :namespaces, Types::Hash.map(Types::Symbol, Namespace).default({}.freeze)
|
50
|
+
|
51
|
+
# Human-readable description of this namespace
|
52
|
+
# @return [String, nil] Description text
|
21
53
|
attribute :description, Types::String.optional.default(nil)
|
22
54
|
|
23
|
-
# Get the full path of this namespace
|
55
|
+
# Get the full path of this namespace including parent namespaces
|
56
|
+
# @param parent_path [Array<Symbol>] Array of parent namespace names
|
57
|
+
# @return [Array<Symbol>] Full namespace path
|
58
|
+
# @example
|
59
|
+
# namespace.full_path([:web, :api]) # => [:web, :api, :request]
|
24
60
|
def full_path(parent_path = [])
|
25
61
|
return [name] if parent_path.empty?
|
26
62
|
|
@@ -28,72 +64,109 @@ module Datadog
|
|
28
64
|
end
|
29
65
|
|
30
66
|
# Find a metric by name within this namespace
|
67
|
+
# @param metric_name [String, Symbol] Name of the metric to find
|
68
|
+
# @return [MetricDefinition, nil] The metric definition or nil if not found
|
69
|
+
# @example
|
70
|
+
# namespace.find_metric(:page_views) # => MetricDefinition instance
|
31
71
|
def find_metric(metric_name)
|
32
72
|
metric_symbol = metric_name.to_sym
|
33
73
|
metrics[metric_symbol]
|
34
74
|
end
|
35
75
|
|
36
76
|
# Find a tag definition by name within this namespace
|
77
|
+
# @param tag_name [String, Symbol] Name of the tag to find
|
78
|
+
# @return [TagDefinition, nil] The tag definition or nil if not found
|
79
|
+
# @example
|
80
|
+
# namespace.find_tag(:controller) # => TagDefinition instance
|
37
81
|
def find_tag(tag_name)
|
38
82
|
tag_symbol = tag_name.to_sym
|
39
83
|
tags[tag_symbol]
|
40
84
|
end
|
41
85
|
|
42
86
|
# Find a nested namespace by name
|
87
|
+
# @param namespace_name [String, Symbol] Name of the namespace to find
|
88
|
+
# @return [Namespace, nil] The nested namespace or nil if not found
|
89
|
+
# @example
|
90
|
+
# namespace.find_namespace(:api) # => Namespace instance
|
43
91
|
def find_namespace(namespace_name)
|
44
92
|
namespace_symbol = namespace_name.to_sym
|
45
93
|
namespaces[namespace_symbol]
|
46
94
|
end
|
47
95
|
|
48
|
-
# Add a new metric to this namespace
|
96
|
+
# Add a new metric to this namespace (returns new namespace instance)
|
97
|
+
# @param metric_definition [MetricDefinition] The metric definition to add
|
98
|
+
# @return [Namespace] New namespace instance with the added metric
|
49
99
|
def add_metric(metric_definition)
|
50
100
|
new(metrics: metrics.merge(metric_definition.name => metric_definition))
|
51
101
|
end
|
52
102
|
|
53
|
-
# Add a new tag definition to this namespace
|
103
|
+
# Add a new tag definition to this namespace (returns new namespace instance)
|
104
|
+
# @param tag_definition [TagDefinition] The tag definition to add
|
105
|
+
# @return [Namespace] New namespace instance with the added tag
|
54
106
|
def add_tag(tag_definition)
|
55
107
|
new(tags: tags.merge(tag_definition.name => tag_definition))
|
56
108
|
end
|
57
109
|
|
58
|
-
# Add a nested namespace
|
110
|
+
# Add a nested namespace (returns new namespace instance)
|
111
|
+
# @param namespace [Namespace] The namespace to add
|
112
|
+
# @return [Namespace] New namespace instance with the added namespace
|
59
113
|
def add_namespace(namespace)
|
60
114
|
new(namespaces: namespaces.merge(namespace.name => namespace))
|
61
115
|
end
|
62
116
|
|
63
117
|
# Get all metric names in this namespace (not including nested)
|
118
|
+
# @return [Array<Symbol>] Array of metric names
|
64
119
|
def metric_names
|
65
120
|
metrics.keys
|
66
121
|
end
|
67
122
|
|
68
123
|
# Get all tag names in this namespace
|
124
|
+
# @return [Array<Symbol>] Array of tag names
|
69
125
|
def tag_names
|
70
126
|
tags.keys
|
71
127
|
end
|
72
128
|
|
73
129
|
# Get all nested namespace names
|
130
|
+
# @return [Array<Symbol>] Array of namespace names
|
74
131
|
def namespace_names
|
75
132
|
namespaces.keys
|
76
133
|
end
|
77
134
|
|
78
135
|
# Check if this namespace contains a metric
|
136
|
+
# @param metric_name [String, Symbol] Name of the metric to check
|
137
|
+
# @return [Boolean] true if metric exists
|
79
138
|
def has_metric?(metric_name)
|
80
139
|
metric_symbol = metric_name.to_sym
|
81
140
|
metrics.key?(metric_symbol)
|
82
141
|
end
|
83
142
|
|
84
143
|
# Check if this namespace contains a tag definition
|
144
|
+
# @param tag_name [String, Symbol] Name of the tag to check
|
145
|
+
# @return [Boolean] true if tag exists
|
85
146
|
def has_tag?(tag_name)
|
86
147
|
tag_symbol = tag_name.to_sym
|
87
148
|
tags.key?(tag_symbol)
|
88
149
|
end
|
89
150
|
|
90
151
|
# Check if this namespace contains a nested namespace
|
152
|
+
# @param namespace_name [String, Symbol] Name of the namespace to check
|
153
|
+
# @return [Boolean] true if namespace exists
|
91
154
|
def has_namespace?(namespace_name)
|
92
155
|
namespace_symbol = namespace_name.to_sym
|
93
156
|
namespaces.key?(namespace_symbol)
|
94
157
|
end
|
95
158
|
|
96
159
|
# Get all metrics recursively including from nested namespaces
|
160
|
+
# @param path [Array<Symbol>] Current namespace path (used for recursion)
|
161
|
+
# @return [Hash] Hash mapping full metric names to metric info
|
162
|
+
# @example
|
163
|
+
# {
|
164
|
+
# "web.page_views" => {
|
165
|
+
# definition: MetricDefinition,
|
166
|
+
# namespace_path: [:web],
|
167
|
+
# namespace: Namespace
|
168
|
+
# }
|
169
|
+
# }
|
97
170
|
def all_metrics(path = [])
|
98
171
|
# Filter out :root from the path to avoid it appearing in metric names
|
99
172
|
current_path = path + [name]
|
@@ -119,11 +192,14 @@ module Datadog
|
|
119
192
|
end
|
120
193
|
|
121
194
|
# Get all tag definitions including inherited from parent namespaces
|
195
|
+
# @param parent_tags [Hash] Tag definitions from parent namespaces
|
196
|
+
# @return [Hash<Symbol, TagDefinition>] Combined tag definitions
|
122
197
|
def effective_tags(parent_tags = {})
|
123
198
|
parent_tags.merge(tags)
|
124
199
|
end
|
125
200
|
|
126
201
|
# Validate that all tag references in metrics exist
|
202
|
+
# @return [Array<String>] Array of validation error messages
|
127
203
|
def validate_tag_references
|
128
204
|
errors = []
|
129
205
|
|
@@ -148,6 +224,10 @@ module Datadog
|
|
148
224
|
end
|
149
225
|
|
150
226
|
# Find metric by path (e.g., "request.duration" within web namespace)
|
227
|
+
# @param path [String] Dot-separated path to the metric
|
228
|
+
# @return [MetricDefinition, nil] The metric definition or nil if not found
|
229
|
+
# @example
|
230
|
+
# namespace.find_metric_by_path("api.requests") # => MetricDefinition
|
151
231
|
def find_metric_by_path(path)
|
152
232
|
parts = path.split(".")
|
153
233
|
|
@@ -167,6 +247,10 @@ module Datadog
|
|
167
247
|
end
|
168
248
|
|
169
249
|
# Get namespace by path (e.g., "web.request")
|
250
|
+
# @param path [String] Dot-separated path to the namespace
|
251
|
+
# @return [Namespace, nil] The namespace or nil if not found
|
252
|
+
# @example
|
253
|
+
# root_namespace.find_namespace_by_path("web.api") # => Namespace
|
170
254
|
def find_namespace_by_path(path)
|
171
255
|
return self if path.empty?
|
172
256
|
|
@@ -186,11 +270,13 @@ module Datadog
|
|
186
270
|
end
|
187
271
|
|
188
272
|
# Count total metrics including nested namespaces
|
273
|
+
# @return [Integer] Total number of metrics in this namespace tree
|
189
274
|
def total_metrics_count
|
190
275
|
metrics.count + namespaces.values.sum(&:total_metrics_count)
|
191
276
|
end
|
192
277
|
|
193
278
|
# Count total namespaces including nested
|
279
|
+
# @return [Integer] Total number of namespaces in this namespace tree
|
194
280
|
def total_namespaces_count
|
195
281
|
namespaces.count + namespaces.values.sum(&:total_namespaces_count)
|
196
282
|
end
|