fluent-plugin-datadog 0.15.0 → 0.15.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ada0477abc2674f1139d27ee6aa58cca24dc4c0f23414a651432b2d1689729e
4
- data.tar.gz: c2e02ecf94b0453bad5bc2b8683396b8a0a02faba89b17e46d925a25e80ccda1
3
+ metadata.gz: a972214999befc7ccaf2a687d6a5f08007b381c3722998523e58d1058515a802
4
+ data.tar.gz: 1be2db9c9b926019eb917aa4973ffde6243fb2d013072b74965c2e4d32dd21ab
5
5
  SHA512:
6
- metadata.gz: 6da0566bf7b59b6316ef98fdefa74b1626cd0a21be8a4080b014a617db9f769a3c0cc4cb502c3526d4aefa00dea7cef0f744ebc77fb2c4f9a23dc8689ee71436
7
- data.tar.gz: d2d6f2b098a9290f75d4a217b0fe5803306161a04bfdfb59d918f4d7a0ec335a46def23c74f0e84e8eb27797f5dcc09fc393ae23e0df96a7a526c8e0fb31738e
6
+ metadata.gz: 71b1a131838a953f3f352ee5132a4443b1a7f21f56c031d3f8e13c9409874e34a1c3a79c96e0a964bcb2c7b205d1f02ad2f3a22208087bf39358d456d8f7b8ad
7
+ data.tar.gz: 7082da59a80ea386ae4e4152755fc48fcdb5931dc53f80d9c41eecab2d4aa7f3a0f0e12428403dff48d5b91358b7d947b04cbc764c136561cb6abb9285118b09
data/README.md CHANGED
@@ -100,7 +100,8 @@ As `fluent-plugin-datadog` is a buffered output plugin, you can set all of the b
100
100
  | **dd_hostname** | Used by Datadog to identify the host submitting the logs. | `hostname -f` |
101
101
  | **service** | Used by Datadog to correlate between logs, traces and metrics. | nil |
102
102
  | **port** | Proxy port when logs are not directly forwarded to Datadog and ssl is not used | 80 |
103
- | **host** | Proxy endpoint when logs are not directly forwarded to Datadog | http-intake.logs.datadoghq.com |
103
+ | **site** | The Datadog [site](https://docs.datadoghq.com/getting_started/site/) to send logs to. Used to derive the default `host` when no explicit `host` is provided. Valid values: `datadoghq.com`, `datadoghq.eu`, `us3.datadoghq.com`, `us5.datadoghq.com`, `ap1.datadoghq.com`, `ddog-gov.com`. | datadoghq.com |
104
+ | **host** | Proxy endpoint when logs are not directly forwarded to Datadog. When unset, the default is derived from `site` as `http-intake.logs.<site>`. An explicitly configured `host` always wins over `site`. | (derived from `site`) |
104
105
  | **http_proxy** | HTTP proxy, only takes effect if HTTP forwarding is enabled (`use_http`). Defaults to `HTTP_PROXY`/`http_proxy` env vars. | nil |
105
106
  | **delete_extracted_tag_attributes** | When true, removes `kubernetes` and `docker` attributes from log records after extracting them as tags. Useful to avoid duplicate data in Datadog logs UI. | false |
106
107
 
@@ -149,15 +150,23 @@ Configuration example:
149
150
 
150
151
  ## Build
151
152
 
152
- To build a new version of this plugin and push it to RubyGems:
153
+ To build the gem locally:
153
154
 
154
- - Update the version in the .gemspec file accordingly
155
155
  - `rake build` to build the gem file
156
- - `rake release` to push the new gem to RubyGems
157
156
 
158
- **Note**: The latest command will fail without appropriate credentials configured. You can set those credentials by running the following command:
157
+ ## Releasing
159
158
 
160
- `curl -u <USERNAME> https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials`, it will ask for your password.
159
+ This gem is published to RubyGems via a GitHub Actions [Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) workflow. No API keys or local credentials are needed.
160
+
161
+ To release a new version:
162
+
163
+ 1. Update the version in `lib/fluent/plugin/version.rb`
164
+ 2. Update `CHANGELOG.md`
165
+ 3. Merge to `master`
166
+ 4. Go to **Actions** > **Publish gem** > **Run workflow**
167
+ 5. Run with `push` unchecked first (dry run) to verify the build
168
+ 6. Run again with `push` checked to publish to RubyGems
169
+ 7. The `rubygems.org` environment gate will ask for approval before publishing
161
170
 
162
171
  ## Development Environment
163
172
 
@@ -24,7 +24,9 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
24
24
  DD_MAX_BATCH_SIZE = 5000000
25
25
  DD_TRUNCATION_SUFFIX = "...TRUNCATED..."
26
26
 
27
- DD_DEFAULT_HTTP_ENDPOINT = "http-intake.logs.datadoghq.com"
27
+ DD_DEFAULT_SITE = "datadoghq.com"
28
+ DD_DEFAULT_HTTP_HOST_PREFIX = "http-intake.logs."
29
+ DD_DEFAULT_HTTP_ENDPOINT = "#{DD_DEFAULT_HTTP_HOST_PREFIX}#{DD_DEFAULT_SITE}".freeze
28
30
  DD_DEFAULT_TCP_ENDPOINT = "intake.logs.datadoghq.com"
29
31
 
30
32
  helpers :compat_parameters
@@ -45,8 +47,16 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
45
47
  config_param :dd_hostname, :string, :default => nil
46
48
  config_param :delete_extracted_tag_attributes, :bool, :default => false
47
49
 
50
+ # Datadog site used to derive the default intake host. Valid values include:
51
+ # "datadoghq.com" (default), "datadoghq.eu", "us3.datadoghq.com",
52
+ # "us5.datadoghq.com", "ap1.datadoghq.com", "ddog-gov.com". Any value
53
+ # explicitly set for `host` takes precedence over the site-derived default.
54
+ config_param :site, :string, :default => DD_DEFAULT_SITE
55
+
48
56
  # Connection settings
49
- config_param :host, :string, :default => DD_DEFAULT_HTTP_ENDPOINT
57
+ # `host` defaults to nil so we can tell whether the user explicitly set it.
58
+ # When nil, the host is derived from `site` during `configure`.
59
+ config_param :host, :string, :default => nil
50
60
  config_param :use_ssl, :bool, :default => true
51
61
  config_param :port, :integer, :default => 80
52
62
  config_param :ssl_port, :integer, :default => 443
@@ -77,12 +87,29 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
77
87
  def configure(conf)
78
88
  compat_parameters_convert(conf, :buffer)
79
89
  super
80
- return if @dd_hostname
81
90
 
82
- if not @use_http and @host == DD_DEFAULT_HTTP_ENDPOINT
83
- @host = DD_DEFAULT_TCP_ENDPOINT
91
+ # Derive default host from `site` only for HTTP transport.
92
+ # TCP users with a non-default site must set `host` explicitly;
93
+ # TCP users with no host and the default site get the legacy TCP endpoint.
94
+ if @host.nil? || @host.empty?
95
+ if @use_http
96
+ @host = "#{DD_DEFAULT_HTTP_HOST_PREFIX}#{@site}"
97
+ elsif @site == DD_DEFAULT_SITE
98
+ @host = DD_DEFAULT_TCP_ENDPOINT
99
+ else
100
+ # TCP + non-default site: we cannot safely derive a TCP intake hostname
101
+ # from `site` (the HTTP-intake prefix is HTTP-only), and leaving @host
102
+ # nil would surface as a cryptic connect-time error. Fail fast at
103
+ # configure time with an actionable message.
104
+ raise Fluent::ConfigError,
105
+ "`host` is required when `use_http false` is combined with a non-default `site` " \
106
+ "(`site #{@site.inspect}`). Set `host` explicitly to your TCP intake (e.g. " \
107
+ "`intake.logs.#{@site}`)."
108
+ end
84
109
  end
85
110
 
111
+ return if @dd_hostname
112
+
86
113
  # Set dd_hostname if not already set (can be set when using fluentd as aggregator)
87
114
  @dd_hostname = %x[hostname -f 2> /dev/null].strip
88
115
  @dd_hostname = Socket.gethostname if @dd_hostname.empty?
@@ -148,8 +175,9 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
148
175
  process_tcp_event(record[0], @max_retries, @max_backoff, DD_MAX_BATCH_SIZE)
149
176
  end
150
177
  end
151
- rescue Exception => e
152
- log.error("Uncaught processing exception in datadog forwarder #{e.message}")
178
+ rescue StandardError => e
179
+ log.error("Processing exception in datadog forwarder #{e.class}: #{e.message}")
180
+ raise
153
181
  end
154
182
  end
155
183
 
@@ -301,6 +329,10 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
301
329
  retries += 1
302
330
  retry
303
331
  end
332
+ # Bounded retries exhausted: re-raise so the caller (and, ultimately,
333
+ # Fluentd core's buffer retry) is signalled instead of the failure being
334
+ # swallowed and the chunk silently dropped.
335
+ raise
304
336
  end
305
337
  end
306
338
 
@@ -318,6 +350,28 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
318
350
  require 'net/http'
319
351
  require 'net/http/persistent'
320
352
 
353
+ # Transient network exceptions that warrant a retry. This mirrors the set
354
+ # Ruby's Net::HTTP retries for idempotent requests (see
355
+ # Net::HTTP#max_retries=), which notably does NOT include POST, plus the
356
+ # connection-establishment errors net-http-persistent wraps in its own
357
+ # Error. Because our log POSTs are non-idempotent, Net::HTTP will not retry
358
+ # them for us, so we classify these ourselves and route them through
359
+ # send_retries (and, on exhaustion, up to Fluentd core).
360
+ RETRYABLE_NETWORK_EXCEPTIONS = [
361
+ Net::OpenTimeout,
362
+ Net::ReadTimeout,
363
+ EOFError,
364
+ IOError,
365
+ SocketError,
366
+ Errno::ECONNRESET,
367
+ Errno::ECONNREFUSED,
368
+ Errno::ECONNABORTED,
369
+ Errno::EPIPE,
370
+ Errno::ETIMEDOUT,
371
+ OpenSSL::SSL::SSLError,
372
+ Net::HTTP::Persistent::Error,
373
+ ].freeze
374
+
321
375
  def initialize(logger, use_ssl, no_ssl_validation, host, ssl_port, port, http_proxy, custom_headers, use_compression, api_key, force_v1_routes = false)
322
376
  @logger = logger
323
377
  protocol = use_ssl ? "https" : "http"
@@ -357,7 +411,13 @@ class Fluent::DatadogOutput < Fluent::Plugin::Output
357
411
  def send(payload)
358
412
  request = Net::HTTP::Post.new @uri.request_uri
359
413
  request.body = payload
360
- response = @client.request @uri, request
414
+ begin
415
+ response = @client.request @uri, request
416
+ rescue *RETRYABLE_NETWORK_EXCEPTIONS => e
417
+ # Transient network failure before we ever saw a response. Net::HTTP
418
+ # won't retry a POST for us, so surface it as retryable.
419
+ raise RetryableError.new "Unable to send payload, transient network error: #{e.class}: #{e.message}"
420
+ end
361
421
  res_code = response.code.to_i
362
422
  # on a backend error or on an http 429, retry with backoff
363
423
  if res_code >= 500 || res_code == 429
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatadogFluentPlugin
4
- VERSION = '0.15.0'
4
+ VERSION = '0.15.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog Solutions Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-18 00:00:00.000000000 Z
11
+ date: 2026-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -152,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
152
  - !ruby/object:Gem::Version
153
153
  version: '0'
154
154
  requirements: []
155
- rubygems_version: 3.4.10
155
+ rubygems_version: 3.5.22
156
156
  signing_key:
157
157
  specification_version: 4
158
158
  summary: Datadog output plugin for Fluent event collector