|
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 |
@@ -188,12 +194,19 @@ def __init__( |
188 | 194 |
|
189 | 195 | >>> statsd = DogStatsd() |
190 | 196 |
|
| 197 | + :envvar DD_DOGSTATSD_URL: the connection information for the dogstatsd server. |
| 198 | + If set, it overrides the default values. |
| 199 | + Example for UDP url: `DD_DOGSTATSD_URL=udp://localhost:8125` |
| 200 | + Example for UDS: `DD_DOGSTATSD_URL=unix:///var/run/datadog/dsd.socket` |
| 201 | + Windows named pipes are currently unsupported. |
| 202 | + :type DD_DOGSTATSD_URL: string |
| 203 | +
|
191 | 204 | :envvar DD_AGENT_HOST: the host of the DogStatsd server. |
192 | | - If set, it overrides default value. |
| 205 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
193 | 206 | :type DD_AGENT_HOST: string |
194 | 207 |
|
195 | 208 | :envvar DD_DOGSTATSD_PORT: the port of the DogStatsd server. |
196 | | - If set, it overrides default value. |
| 209 | + If set, it overrides default value. DD_DOGSTATSD_URL takes precedence over this value. |
197 | 210 | :type DD_DOGSTATSD_PORT: integer |
198 | 211 |
|
199 | 212 | :envvar DATADOG_TAGS: Tags to attach to every metric reported by dogstatsd client. |
@@ -374,22 +387,8 @@ def __init__( |
374 | 387 | # Check for deprecated option |
375 | 388 | if max_buffer_size is not None: |
376 | 389 | log.warning("The parameter max_buffer_size is now deprecated and is not used anymore") |
377 | | - # Check host and port env vars |
378 | | - agent_host = os.environ.get("DD_AGENT_HOST") |
379 | | - if agent_host and host == DEFAULT_HOST: |
380 | | - host = agent_host |
381 | 390 |
|
382 | | - dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
383 | | - if dogstatsd_port and port == DEFAULT_PORT: |
384 | | - try: |
385 | | - port = int(dogstatsd_port) |
386 | | - except ValueError: |
387 | | - log.warning( |
388 | | - "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
389 | | - %s, using %s as port number", |
390 | | - dogstatsd_port, |
391 | | - port, |
392 | | - ) |
| 391 | + host, port, socket_path = self._parse_env_connection_overrides(host, port, socket_path) |
393 | 392 |
|
394 | 393 | # Assuming environment variables always override |
395 | 394 | telemetry_host = os.environ.get("DD_TELEMETRY_HOST", telemetry_host) |
@@ -601,6 +600,74 @@ def disable_telemetry(self): |
601 | 600 | def enable_telemetry(self): |
602 | 601 | self._telemetry = True |
603 | 602 |
|
| 603 | + def _parse_env_connection_overrides(self, host, port, socket_path): |
| 604 | + dogstatsd_url = os.environ.get("DD_DOGSTATSD_URL") |
| 605 | + |
| 606 | + if ( |
| 607 | + host == DEFAULT_HOST |
| 608 | + and port == DEFAULT_PORT |
| 609 | + and socket_path is None |
| 610 | + and dogstatsd_url is not None |
| 611 | + ): |
| 612 | + parsed = urlparse(dogstatsd_url) |
| 613 | + # If all values are defaults, prefer DD_DOGSTATSD_URL if present. |
| 614 | + if parsed.scheme == "unix": |
| 615 | + log.debug( |
| 616 | + "Found a DD_DOGSTATSD_URL matching the uds syntax, " |
| 617 | + "setting socket path %s.", dogstatsd_url |
| 618 | + ) |
| 619 | + return host, port, dogstatsd_url |
| 620 | + |
| 621 | + elif dogstatsd_url.startswith(WINDOWS_NAMEDPIPE_SCHEME): |
| 622 | + log.debug( |
| 623 | + "DD_DOGSTATSD_URL is configured to utilize a windows named pipe, " |
| 624 | + "which is not currently supported by datadogpy. Falling back to " |
| 625 | + "alternate connection identifiers." |
| 626 | + ) |
| 627 | + |
| 628 | + elif parsed.scheme == "udp": |
| 629 | + try: |
| 630 | + p_port = parsed.port |
| 631 | + # Python 2 doesn't automatically perform bounds checking on the port |
| 632 | + if p_port is None or p_port < 0 or p_port > 65535: |
| 633 | + log.debug("Invalid port number provided, reverting to default port") |
| 634 | + p_port = DEFAULT_PORT |
| 635 | + except ValueError: |
| 636 | + log.debug("Invalid port number provided, reverting to default port") |
| 637 | + p_port = DEFAULT_PORT |
| 638 | + |
| 639 | + log.debug( |
| 640 | + "Found a DD_DOGSTATSD_URL matching the udp sytnax, " |
| 641 | + "setting host and port %s:%d.", parsed.hostname, p_port |
| 642 | + ) |
| 643 | + |
| 644 | + return parsed.hostname, p_port, socket_path |
| 645 | + else: |
| 646 | + log.debug( |
| 647 | + "Unable to parse DD_DOGSTATSD_URL, did you remember to prefix the url " |
| 648 | + "with 'unix://' or 'udp://'? Falling back to alternate " |
| 649 | + "connection identifiers." |
| 650 | + ) |
| 651 | + |
| 652 | + # We either have some non-default values or no DD_DOGSTATSD_URL |
| 653 | + # Check host and port env vars |
| 654 | + agent_host = os.environ.get("DD_AGENT_HOST") |
| 655 | + if agent_host and host == DEFAULT_HOST: |
| 656 | + host = agent_host |
| 657 | + |
| 658 | + dogstatsd_port = os.environ.get("DD_DOGSTATSD_PORT") |
| 659 | + if dogstatsd_port and port == DEFAULT_PORT: |
| 660 | + try: |
| 661 | + port = int(dogstatsd_port) |
| 662 | + except ValueError: |
| 663 | + log.warning( |
| 664 | + "Port number provided in DD_DOGSTATSD_PORT env var is not an integer: \ |
| 665 | + %s, using %s as port number", |
| 666 | + dogstatsd_port, |
| 667 | + port, |
| 668 | + ) |
| 669 | + return host, port, socket_path |
| 670 | + |
604 | 671 | # Note: Invocations of this method should be thread-safe |
605 | 672 | def _start_flush_thread(self): |
606 | 673 | if self._disable_aggregation and self.disable_buffering: |
|
0 commit comments