Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions datadog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def initialize(
statsd_constant_tags=None, # type: Optional[List[str]]
return_raw_response=False, # type: bool
hostname_from_config=True, # type: bool
cardinality=None, # type: Optional[str]
**kwargs # type: Any
):
# type: (...) -> None
Expand Down Expand Up @@ -117,6 +118,12 @@ def initialize(

:param hostname_from_config: Set the hostname from the Datadog agent config (agent 5). Will be deprecated
:type hostname_from_config: boolean

:param cardinality: Set the global cardinality for all metrics. \
Possible values are "none", "low", "orchestrator" and "high".
Can also be set via the DATADOG_CARDINALITY or DD_CARDINALITY environment variables.
:type cardinality: string

"""
# API configuration
api._api_key = api_key or api._api_key or os.environ.get("DATADOG_API_KEY", os.environ.get("DD_API_KEY"))
Expand Down Expand Up @@ -151,6 +158,9 @@ def initialize(
statsd.disable_buffering = statsd_disable_buffering
api._return_raw_response = return_raw_response

# Set the global cardinality for all metrics
statsd.cardinality = cardinality or os.environ.get("DATADOG_CARDINALITY", os.environ.get("DD_CARDINALITY"))

# HTTP client and API options
for key, value in iteritems(kwargs):
attribute = "_{}".format(key)
Expand Down
42 changes: 25 additions & 17 deletions datadog/dogstatsd/aggregator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
)
from datadog.dogstatsd.metric_types import MetricType
from datadog.dogstatsd.max_sample_metric_context import MaxSampleMetricContexts
from datadog.util.format import validate_cardinality


class Aggregator(object):
def __init__(self, max_samples_per_context=0):
def __init__(self, max_samples_per_context=0, cardinality=None):
self.max_samples_per_context = max_samples_per_context
self.metrics_map = {
MetricType.COUNT: {},
Expand All @@ -31,6 +32,7 @@ def __init__(self, max_samples_per_context=0):
MetricType.GAUGE: threading.RLock(),
MetricType.SET: threading.RLock(),
}
self.cardinality = cardinality

def flush_aggregated_metrics(self):
metrics = []
Expand Down Expand Up @@ -58,53 +60,59 @@ def get_context(self, name, tags):
tags_str = ",".join(tags) if tags is not None else ""
return "{}:{}".format(name, tags_str)

def count(self, name, value, tags, rate, timestamp=0):
def count(self, name, value, tags, rate, timestamp=0, cardinality=None):
return self.add_metric(
MetricType.COUNT, CountMetric, name, value, tags, rate, timestamp
MetricType.COUNT, CountMetric, name, value, tags, rate, timestamp, cardinality
)

def gauge(self, name, value, tags, rate, timestamp=0):
def gauge(self, name, value, tags, rate, timestamp=0, cardinality=None):
return self.add_metric(
MetricType.GAUGE, GaugeMetric, name, value, tags, rate, timestamp
MetricType.GAUGE, GaugeMetric, name, value, tags, rate, timestamp, cardinality
)

def set(self, name, value, tags, rate, timestamp=0):
def set(self, name, value, tags, rate, timestamp=0, cardinality=None):
return self.add_metric(
MetricType.SET, SetMetric, name, value, tags, rate, timestamp
MetricType.SET, SetMetric, name, value, tags, rate, timestamp, cardinality
)

def add_metric(
self, metric_type, metric_class, name, value, tags, rate, timestamp=0
self, metric_type, metric_class, name, value, tags, rate, timestamp=0, cardinality=None
):
context = self.get_context(name, tags)
with self._locks[metric_type]:
if context in self.metrics_map[metric_type]:
self.metrics_map[metric_type][context].aggregate(value)
else:
if cardinality is None:
cardinality = self.cardinality
validate_cardinality(cardinality)
self.metrics_map[metric_type][context] = metric_class(
name, value, tags, rate, timestamp
name, value, tags, rate, timestamp, cardinality
)

def histogram(self, name, value, tags, rate):
def histogram(self, name, value, tags, rate, cardinality=None):
return self.add_max_sample_metric(
MetricType.HISTOGRAM, name, value, tags, rate
MetricType.HISTOGRAM, name, value, tags, rate, cardinality
)

def distribution(self, name, value, tags, rate):
def distribution(self, name, value, tags, rate, cardinality=None):
return self.add_max_sample_metric(
MetricType.DISTRIBUTION, name, value, tags, rate
MetricType.DISTRIBUTION, name, value, tags, rate, cardinality
)

def timing(self, name, value, tags, rate):
def timing(self, name, value, tags, rate, cardinality=None):
return self.add_max_sample_metric(
MetricType.TIMING, name, value, tags, rate
MetricType.TIMING, name, value, tags, rate, cardinality
)

def add_max_sample_metric(
self, metric_type, name, value, tags, rate
self, metric_type, name, value, tags, rate, cardinality=None
):
if rate is None:
rate = 1
context_key = self.get_context(name, tags)
metric_context = self.max_sample_metric_map[metric_type]
return metric_context.sample(name, value, tags, rate, context_key, self.max_samples_per_context)
if cardinality is None:
cardinality = self.cardinality
validate_cardinality(cardinality)
return metric_context.sample(name, value, tags, rate, context_key, self.max_samples_per_context, cardinality)
Loading
Loading