|
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 |
@@ -181,12 +187,19 @@ def __init__( |
181 | 187 |
|
182 | 188 | >>> statsd = DogStatsd() |
183 | 189 |
|
| 190 | + :envvar DD_DOGSTATSD_URL: the connection information for the dogstatsd server. |
| 191 | + If set, it overrides the default values. |
| 192 | + Example for UDP url: `DD_DOGSTATSD_URL=udp://localhost:8125` |
| 193 | + Example for UDS: `DD_DOGSTATSD_URL=unix:///var/run/datadog/dsd.socket` |
| 194 | + Windows named pipes are currently unsupported. |
| 195 | + :type DD_DOGSTATSD_URL: string |
| 196 | +
|
184 | 197 | :envvar DD_AGENT_HOST: the host of the DogStatsd server. |
185 | | - If set, it overrides default value. |
| 198 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
186 | 199 | :type DD_AGENT_HOST: string |
187 | 200 |
|
188 | 201 | :envvar DD_DOGSTATSD_PORT: the port of the DogStatsd server. |
189 | | - If set, it overrides default value. |
| 202 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
190 | 203 | :type DD_DOGSTATSD_PORT: integer |
191 | 204 |
|
192 | 205 | :envvar DATADOG_TAGS: Tags to attach to every metric reported by dogstatsd client. |
@@ -359,22 +372,8 @@ def __init__( |
359 | 372 | # Check for deprecated option |
360 | 373 | if max_buffer_size is not None: |
361 | 374 | log.warning("The parameter max_buffer_size is now deprecated and is not used anymore") |
362 | | - # Check host and port env vars |
363 | | - agent_host = os.environ.get("DD_AGENT_HOST") |
364 | | - if agent_host and host == DEFAULT_HOST: |
365 | | - host = agent_host |
366 | 375 |
|
367 | | - dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
368 | | - if dogstatsd_port and port == DEFAULT_PORT: |
369 | | - try: |
370 | | - port = int(dogstatsd_port) |
371 | | - except ValueError: |
372 | | - log.warning( |
373 | | - "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
374 | | - %s, using %s as port number", |
375 | | - dogstatsd_port, |
376 | | - port, |
377 | | - ) |
| 376 | + host, port, socket_path = self._parse_env_connection_overrides(host, port, socket_path) |
378 | 377 |
|
379 | 378 | # Assuming environment variables always override |
380 | 379 | telemetry_host = os.environ.get("DD_TELEMETRY_HOST", telemetry_host) |
@@ -585,6 +584,74 @@ def disable_telemetry(self): |
585 | 584 | def enable_telemetry(self): |
586 | 585 | self._telemetry = True |
587 | 586 |
|
| 587 | + def _parse_env_connection_overrides(self, host, port, socket_path): |
| 588 | + dogstatsd_url = os.environ.get("DD_DOGSTATSD_URL") |
| 589 | + |
| 590 | + if ( |
| 591 | + host == DEFAULT_HOST |
| 592 | + and port == DEFAULT_PORT |
| 593 | + and socket_path is None |
| 594 | + and dogstatsd_url is not None |
| 595 | + ): |
| 596 | + parsed = urlparse(dogstatsd_url) |
| 597 | + # If all values are defaults, prefer DD_DOGSTATSD_URL if present. |
| 598 | + if parsed.scheme == "unix": |
| 599 | + log.debug( |
| 600 | + "Found a DD_DOGSTATSD_URL matching the uds syntax, " |
| 601 | + "setting socket path %s.", dogstatsd_url |
| 602 | + ) |
| 603 | + return host, port, dogstatsd_url |
| 604 | + |
| 605 | + elif dogstatsd_url.startswith(WINDOWS_NAMEDPIPE_SCHEME): |
| 606 | + log.debug( |
| 607 | + "DD_DOGSTATSD_URL is configured to utilize a windows named pipe, " |
| 608 | + "which is not currently supported by datadogpy. Falling back to " |
| 609 | + "alternate connection identifiers." |
| 610 | + ) |
| 611 | + |
| 612 | + elif parsed.scheme == "udp": |
| 613 | + try: |
| 614 | + p_port = parsed.port |
| 615 | + # Python 2 doesn't automatically perform bounds checking on the port |
| 616 | + if p_port is None or p_port < 0 or p_port > 65535: |
| 617 | + log.debug("Invalid port number provided, reverting to default port") |
| 618 | + p_port = DEFAULT_PORT |
| 619 | + except ValueError: |
| 620 | + log.debug("Invalid port number provided, reverting to default port") |
| 621 | + p_port = DEFAULT_PORT |
| 622 | + |
| 623 | + log.debug( |
| 624 | + "Found a DD_DOGSTATSD_URL matching the udp sytnax, " |
| 625 | + "setting host and port %s:%d.", parsed.hostname, p_port |
| 626 | + ) |
| 627 | + |
| 628 | + return parsed.hostname, p_port, socket_path |
| 629 | + else: |
| 630 | + log.debug( |
| 631 | + "Unable to parse DD_DOGSTATSD_URL, did you remember to prefix the url " |
| 632 | + "with 'unix://' or 'udp://'? Falling back to alternate " |
| 633 | + "connection identifiers." |
| 634 | + ) |
| 635 | + |
| 636 | + # We either have some non-default values or no DD_DOGSTATSD_URL |
| 637 | + # Check host and port env vars |
| 638 | + agent_host = os.environ.get("DD_AGENT_HOST") |
| 639 | + if agent_host and host == DEFAULT_HOST: |
| 640 | + host = agent_host |
| 641 | + |
| 642 | + dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
| 643 | + if dogstatsd_port and port == DEFAULT_PORT: |
| 644 | + try: |
| 645 | + port = int(dogstatsd_port) |
| 646 | + except ValueError: |
| 647 | + log.warning( |
| 648 | + "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
| 649 | + %s, using %s as port number", |
| 650 | + dogstatsd_port, |
| 651 | + port, |
| 652 | + ) |
| 653 | + return host, port, socket_path |
| 654 | + |
588 | 655 | # Note: Invocations of this method should be thread-safe |
589 | 656 | def _start_flush_thread(self): |
590 | 657 | if self._disable_aggregation and self.disable_buffering: |
|
0 commit comments