|
25 | 25 | # pypy has the same module, but capitalized. |
26 | 26 | import Queue as queue # type: ignore[no-redef] |
27 | 27 |
|
| 28 | +try: |
| 29 | + from urllib.parse import urlparse # type: ignore |
| 30 | +except ImportError: |
| 31 | + # Python 2 has the same functionality stored under a different module. |
| 32 | + from urlparse import urlparse # type: ignore |
28 | 33 |
|
29 | 34 | # pylint: disable=unused-import |
30 | 35 | from typing import Optional, List, Text, Union |
|
54 | 59 | UNIX_ADDRESS_SCHEME = "unix://" |
55 | 60 | UNIX_ADDRESS_DATAGRAM_SCHEME = "unixgram://" |
56 | 61 | UNIX_ADDRESS_STREAM_SCHEME = "unixstream://" |
| 62 | +WINDOWS_NAMEDPIPE_SCHEME = "\\\\.\\pipe\\" |
57 | 63 |
|
58 | 64 | # Buffering-related values (in seconds) |
59 | 65 | DEFAULT_BUFFERING_FLUSH_INTERVAL = 0.3 |
@@ -180,12 +186,19 @@ def __init__( |
180 | 186 |
|
181 | 187 | >>> statsd = DogStatsd() |
182 | 188 |
|
| 189 | + :envvar DD_DOGSTATSD_URL: the connection information for the dogstatsd server. |
| 190 | + If set, it overrides the default values. |
| 191 | + Example for UDP url: `DD_DOGSTATSD_URL=udp://localhost:8125` |
| 192 | + Example for UDS: `DD_DOGSTATSD_URL=unix:///var/run/datadog/dsd.socket` |
| 193 | + Windows named pipes are currently unsupported. |
| 194 | + :type DD_DOGSTATSD_URL: string |
| 195 | +
|
183 | 196 | :envvar DD_AGENT_HOST: the host of the DogStatsd server. |
184 | | - If set, it overrides default value. |
| 197 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
185 | 198 | :type DD_AGENT_HOST: string |
186 | 199 |
|
187 | 200 | :envvar DD_DOGSTATSD_PORT: the port of the DogStatsd server. |
188 | | - If set, it overrides default value. |
| 201 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
189 | 202 | :type DD_DOGSTATSD_PORT: integer |
190 | 203 |
|
191 | 204 | :envvar DATADOG_TAGS: Tags to attach to every metric reported by dogstatsd client. |
@@ -353,22 +366,8 @@ def __init__( |
353 | 366 | # Check for deprecated option |
354 | 367 | if max_buffer_size is not None: |
355 | 368 | log.warning("The parameter max_buffer_size is now deprecated and is not used anymore") |
356 | | - # Check host and port env vars |
357 | | - agent_host = os.environ.get("DD_AGENT_HOST") |
358 | | - if agent_host and host == DEFAULT_HOST: |
359 | | - host = agent_host |
360 | 369 |
|
361 | | - dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
362 | | - if dogstatsd_port and port == DEFAULT_PORT: |
363 | | - try: |
364 | | - port = int(dogstatsd_port) |
365 | | - except ValueError: |
366 | | - log.warning( |
367 | | - "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
368 | | - %s, using %s as port number", |
369 | | - dogstatsd_port, |
370 | | - port, |
371 | | - ) |
| 370 | + host, port, socket_path = self._parse_env_connection_overrides(host, port, socket_path) |
372 | 371 |
|
373 | 372 | # Assuming environment variables always override |
374 | 373 | telemetry_host = os.environ.get("DD_TELEMETRY_HOST", telemetry_host) |
@@ -574,6 +573,74 @@ def disable_telemetry(self): |
574 | 573 | def enable_telemetry(self): |
575 | 574 | self._telemetry = True |
576 | 575 |
|
| 576 | + def _parse_env_connection_overrides(self, host, port, socket_path): |
| 577 | + dogstatsd_url = os.environ.get("DD_DOGSTATSD_URL") |
| 578 | + |
| 579 | + if ( |
| 580 | + host == DEFAULT_HOST |
| 581 | + and port == DEFAULT_PORT |
| 582 | + and socket_path is None |
| 583 | + and dogstatsd_url is not None |
| 584 | + ): |
| 585 | + parsed = urlparse(dogstatsd_url) |
| 586 | + # If all values are defaults, prefer DD_DOGSTATSD_URL if present. |
| 587 | + if parsed.scheme == "unix": |
| 588 | + log.debug( |
| 589 | + "Found a DD_DOGSTATSD_URL matching the uds syntax, " |
| 590 | + "setting socket path %s.", dogstatsd_url |
| 591 | + ) |
| 592 | + return host, port, dogstatsd_url |
| 593 | + |
| 594 | + elif dogstatsd_url.startswith(WINDOWS_NAMEDPIPE_SCHEME): |
| 595 | + log.debug( |
| 596 | + "DD_DOGSTATSD_URL is configured to utilize a windows named pipe, " |
| 597 | + "which is not currently supported by datadogpy. Falling back to " |
| 598 | + "alternate connection identifiers." |
| 599 | + ) |
| 600 | + |
| 601 | + elif parsed.scheme == "udp": |
| 602 | + try: |
| 603 | + p_port = parsed.port |
| 604 | + # Python 2 doesn't automatically perform bounds checking on the port |
| 605 | + if p_port is None or p_port < 0 or p_port > 65535: |
| 606 | + log.debug("Invalid port number provided, reverting to default port") |
| 607 | + p_port = DEFAULT_PORT |
| 608 | + except ValueError: |
| 609 | + log.debug("Invalid port number provided, reverting to default port") |
| 610 | + p_port = DEFAULT_PORT |
| 611 | + |
| 612 | + log.debug( |
| 613 | + "Found a DD_DOGSTATSD_URL matching the udp sytnax, " |
| 614 | + "setting host and port %s:%d.", parsed.hostname, p_port |
| 615 | + ) |
| 616 | + |
| 617 | + return parsed.hostname, p_port, socket_path |
| 618 | + else: |
| 619 | + log.debug( |
| 620 | + "Unable to parse DD_DOGSTATSD_URL, did you remember to prefix the url " |
| 621 | + "with 'unix://' or 'udp://'? Falling back to alternate " |
| 622 | + "connection identifiers." |
| 623 | + ) |
| 624 | + |
| 625 | + # We either have some non-default values or no DD_DOGSTATSD_URL |
| 626 | + # Check host and port env vars |
| 627 | + agent_host = os.environ.get("DD_AGENT_HOST") |
| 628 | + if agent_host and host == DEFAULT_HOST: |
| 629 | + host = agent_host |
| 630 | + |
| 631 | + dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
| 632 | + if dogstatsd_port and port == DEFAULT_PORT: |
| 633 | + try: |
| 634 | + port = int(dogstatsd_port) |
| 635 | + except ValueError: |
| 636 | + log.warning( |
| 637 | + "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
| 638 | + %s, using %s as port number", |
| 639 | + dogstatsd_port, |
| 640 | + port, |
| 641 | + ) |
| 642 | + return host, port, socket_path |
| 643 | + |
577 | 644 | # Note: Invocations of this method should be thread-safe |
578 | 645 | def _start_flush_thread(self): |
579 | 646 | if self._disable_aggregation and self.disable_buffering: |
|
0 commit comments