fluent-plugin-sumologic-radiant 0.1.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.
data/README.md ADDED
@@ -0,0 +1,469 @@
1
+ # fluent-plugin-sumologic-radiant
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/fluent-plugin-sumologic-radiant.svg)](https://badge.fury.io/rb/fluent-plugin-sumologic-radiant)
4
+ [![Downloads](https://img.shields.io/gem/dt/fluent-plugin-sumologic-radiant.svg)](https://rubygems.org/gems/fluent-plugin-sumologic-radiant)
5
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+ [![Ruby](https://img.shields.io/badge/ruby-3.0+-red.svg)](https://www.ruby-lang.org)
7
+ [![CI](https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/actions/workflows/ci.yml/badge.svg)](https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/actions/workflows/ci.yml)
8
+
9
+ A **modernized and actively maintained** Fluentd output plugin for sending logs and metrics to [Sumo Logic](https://www.sumologic.com) via the [HTTP Collector API](https://help.sumologic.com/docs/send-data/hosted-collectors/http-source/).
10
+
11
+ This is a fork of the original [fluent-plugin-sumologic_output](https://github.com/SumoLogic/fluentd-output-sumologic) by Sumo Logic Inc. This version includes:
12
+
13
+ - ✅ **Ruby 3.x support** (requires Ruby 3.0+)
14
+ - ✅ **Modern dependencies** (Fluentd 1.16+, latest gems)
15
+ - ✅ **Better performance** (using `oj` for JSON, `net-http-persistent` for connections)
16
+ - ✅ **Enhanced security** (TLS 1.2+ by default, custom SSL certificates, updated dependencies)
17
+ - ✅ **Bug fixes** from original plugin (see [Fixed Issues](#fixed-issues-from-original-plugin) below)
18
+ - ✅ **Enhanced debugging** with better error messages and logging
19
+ - ✅ **Active maintenance** and vulnerability management
20
+ - ✅ **Comprehensive test coverage**
21
+
22
+ ## Installation
23
+
24
+ ### RubyGems
25
+
26
+ ```bash
27
+ gem install fluent-plugin-sumologic-radiant
28
+ ```
29
+
30
+ ### Bundler
31
+
32
+ Add to your `Gemfile`:
33
+
34
+ ```ruby
35
+ gem "fluent-plugin-sumologic-radiant"
36
+ ```
37
+
38
+ Then run:
39
+
40
+ ```bash
41
+ bundle install
42
+ ```
43
+
44
+ ### td-agent
45
+
46
+ ```bash
47
+ td-agent-gem install fluent-plugin-sumologic-radiant
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ The plugin is registered as `@type sumologic_radiant`.
53
+
54
+ **📁 Example Configurations**: See the [`examples/`](examples/) directory for complete configuration examples:
55
+ - [`basic.conf`](examples/basic.conf) - Simple configuration for getting started
56
+ - [`kubernetes.conf`](examples/kubernetes.conf) - Kubernetes logs with metadata
57
+ - [`metrics.conf`](examples/metrics.conf) - Metrics in various formats
58
+ - [`ssl-custom-certs.conf`](examples/ssl-custom-certs.conf) - Custom SSL certificates
59
+ - [`advanced.conf`](examples/advanced.conf) - Comprehensive production configuration
60
+
61
+ ### Basic Configuration
62
+
63
+ ```xml
64
+ <match **>
65
+ @type sumologic_radiant
66
+ endpoint https://[SumoEndpoint]/receiver/v1/http/[UniqueHTTPCollectorCode]
67
+ log_format json
68
+ source_category my_category
69
+ source_name my_source
70
+ source_host my_host
71
+ </match>
72
+ ```
73
+
74
+ ### Full Configuration Example
75
+
76
+ ```xml
77
+ <match **>
78
+ @type sumologic_radiant
79
+
80
+ # HTTP Collector endpoint (required)
81
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXX
82
+
83
+ # Source metadata
84
+ source_category production/app/logs
85
+ source_name ${tag}
86
+ source_host ${hostname}
87
+
88
+ # Log formatting
89
+ log_format json # text, json, json_merge, or fields (default: json)
90
+ log_key message # Field to use as log message (when log_format is fields)
91
+ open_timeout 60
92
+ add_timestamp true
93
+ timestamp_key timestamp
94
+
95
+ # Compression
96
+ compress true # Enable gzip compression (default: false)
97
+ compress_encoding gzip # gzip or deflate (default: gzip)
98
+
99
+ # Custom fields
100
+ custom_fields department=engineering,application=myapp
101
+ custom_dimensions cluster=prod,region=us-east
102
+
103
+ # Proxy configuration
104
+ proxy_uri http://proxy.example.com:8080
105
+
106
+ # SSL/TLS
107
+ verify_ssl true # Verify SSL certificates (default: true)
108
+
109
+ # Performance tuning
110
+ disable_cookies true # Disable cookie handling (default: false)
111
+
112
+ # Metadata extraction
113
+ sumo_metadata_key _sumo_metadata # Extract metadata from this field
114
+ </match>
115
+ ```
116
+
117
+ ### Sending Metrics
118
+
119
+ To send metrics to Sumo Logic (requires a metrics HTTP source):
120
+
121
+ ```xml
122
+ <match metrics.**>
123
+ @type sumologic_radiant
124
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXX
125
+ data_type metrics
126
+ metric_data_format graphite # graphite, carbon2, or prometheus (default: graphite)
127
+ source_category production/metrics
128
+
129
+ # Optional: Add dimensions to all metrics
130
+ custom_dimensions cluster=prod,service=api
131
+ </match>
132
+ ```
133
+
134
+ #### Metric Formats
135
+
136
+ **Graphite format:**
137
+ ```
138
+ metric.path value timestamp
139
+ ```
140
+
141
+ **Carbon2 format:**
142
+ ```
143
+ metric=value field1=value1 field2=value2 timestamp
144
+ ```
145
+
146
+ **Prometheus format:**
147
+ ```
148
+ # TYPE metric_name gauge
149
+ metric_name{label1="value1"} value timestamp
150
+ ```
151
+
152
+ ## Configuration Parameters
153
+
154
+ ### Basic Parameters
155
+
156
+ | Parameter | Type | Default | Required | Description |
157
+ |-----------|------|---------|----------|-------------|
158
+ | `endpoint` | string | - | **Yes** | Sumo Logic HTTP collector endpoint URL |
159
+ | `data_type` | enum | `logs` | No | Data type: `logs` or `metrics` |
160
+ | `log_format` | enum | `json` | No | Log format: `text`, `json`, `json_merge`, or `fields` |
161
+ | `metric_data_format` | enum | `graphite` | No | Metric format: `graphite`, `carbon2`, or `prometheus` |
162
+
163
+ ### Source Metadata
164
+
165
+ | Parameter | Type | Default | Description |
166
+ |-----------|------|---------|-------------|
167
+ | `source_category` | string | - | Source category for Sumo Logic |
168
+ | `source_name` | string | - | Source name for Sumo Logic |
169
+ | `source_host` | string | hostname | Source host for Sumo Logic |
170
+ | `source_category_key` | string | - | Extract source category from this field |
171
+ | `source_name_key` | string | - | Extract source name from this field |
172
+ | `source_host_key` | string | - | Extract source host from this field |
173
+
174
+ ### Custom Fields and Dimensions
175
+
176
+ | Parameter | Type | Default | Description |
177
+ |-----------|------|---------|-------------|
178
+ | `custom_fields` | string | - | Comma-separated key=value pairs for custom fields |
179
+ | `custom_dimensions` | string | - | Comma-separated key=value pairs for custom dimensions (metrics only) |
180
+
181
+ ### Compression
182
+
183
+ | Parameter | Type | Default | Description |
184
+ |-----------|------|---------|-------------|
185
+ | `compress` | bool | `false` | Enable compression |
186
+ | `compress_encoding` | enum | `gzip` | Compression type: `gzip` or `deflate` |
187
+
188
+ ### SSL/TLS
189
+
190
+ | Parameter | Type | Default | Description |
191
+ |-----------|------|---------|-------------|
192
+ | `verify_ssl` | bool | `true` | Verify SSL certificates |
193
+ | `ca_file` | string | - | Path to CA certificate file for SSL verification |
194
+ | `ca_path` | string | - | Path to CA certificate directory for SSL verification |
195
+ | `client_cert` | string | - | Path to client certificate file for mutual TLS |
196
+ | `client_key` | string | - | Path to client private key file for mutual TLS |
197
+
198
+ ### Connection Settings
199
+
200
+ | Parameter | Type | Default | Description |
201
+ |-----------|------|---------|-------------|
202
+ | `connect_timeout` | integer | `1` | Connection timeout in seconds |
203
+ | `send_timeout` | integer | `120` | Send timeout in seconds |
204
+ | `receive_timeout` | integer | `60` | Receive timeout in seconds |
205
+ | `open_timeout` | integer | `60` | Open timeout in seconds |
206
+ | `proxy_uri` | string | - | HTTP proxy URI |
207
+ | `disable_cookies` | bool | `false` | Disable cookie handling |
208
+
209
+ ### Advanced
210
+
211
+ | Parameter | Type | Default | Description |
212
+ |-----------|------|---------|-------------|
213
+ | `add_timestamp` | bool | `true` | Add timestamp to logs |
214
+ | `timestamp_key` | string | `timestamp` | Timestamp field name |
215
+ | `log_key` | string | `message` | Log message field (for `fields` format) |
216
+ | `sumo_metadata_key` | string | - | Extract metadata from this field |
217
+
218
+ ## Dynamic Metadata with `_sumo_metadata`
219
+
220
+ You can override source metadata on a per-record basis using the `_sumo_metadata` field:
221
+
222
+ ```ruby
223
+ {
224
+ "message" => "Application error",
225
+ "_sumo_metadata" => {
226
+ "category" => "errors/application",
227
+ "host" => "webserver-01",
228
+ "source" => "app.log"
229
+ }
230
+ }
231
+ ```
232
+
233
+ Enable this feature by setting `sumo_metadata_key`:
234
+
235
+ ```xml
236
+ <match **>
237
+ @type sumologic_radiant
238
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXX
239
+ sumo_metadata_key _sumo_metadata
240
+ </match>
241
+ ```
242
+
243
+ ## Kubernetes Metadata Support
244
+
245
+ **Note**: Issue #50 from the original plugin has been resolved in modern Fluentd versions.
246
+
247
+ ### Using Kubernetes Metadata with Buffer Keys
248
+
249
+ The recommended approach for accessing Kubernetes metadata (e.g., namespace, pod name, container name) is to use Fluentd's buffer chunk keys with the `$` accessor syntax:
250
+
251
+ ```xml
252
+ <match kubernetes.**>
253
+ @type sumologic_radiant
254
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXX
255
+
256
+ # Use Kubernetes metadata in source fields
257
+ source_name ${$.kubernetes.container_name}
258
+ source_category ${$.kubernetes.namespace_name}/${$.kubernetes.pod_name}
259
+
260
+ # Configure buffer to enable placeholder extraction
261
+ <buffer $.kubernetes.namespace_name, $.kubernetes.pod_name, $.kubernetes.container_name>
262
+ @type memory
263
+ flush_interval 5s
264
+ </buffer>
265
+ </match>
266
+ ```
267
+
268
+ ### Alternative: Using Custom Fields
269
+
270
+ You can also include Kubernetes metadata as custom fields:
271
+
272
+ ```xml
273
+ <match kubernetes.**>
274
+ @type sumologic_radiant
275
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXX
276
+
277
+ custom_fields namespace=${$.kubernetes.namespace_name},pod=${$.kubernetes.pod_name},container=${$.kubernetes.container_name}
278
+
279
+ <buffer $.kubernetes.namespace_name, $.kubernetes.pod_name, $.kubernetes.container_name>
280
+ @type memory
281
+ </buffer>
282
+ </match>
283
+ ```
284
+
285
+ ### Why This Works
286
+
287
+ Modern Fluentd (1.16+) supports extracting values from nested record fields using the `$.field.subfield` syntax when declared in buffer chunk keys. This replaces the deprecated `${record['field']}` pattern from older versions.
288
+
289
+ ## Migration from fluent-plugin-sumologic_output
290
+
291
+ This plugin is designed as a **drop-in replacement** for the original `fluent-plugin-sumologic_output`. To migrate:
292
+
293
+ 1. **Update your Gemfile or installation**:
294
+ ```ruby
295
+ # Old
296
+ # gem "fluent-plugin-sumologic_output"
297
+
298
+ # New
299
+ gem "fluent-plugin-sumologic-radiant"
300
+ ```
301
+
302
+ 2. **Update your Fluentd configuration**:
303
+ ```xml
304
+ <match **>
305
+ # Old
306
+ # @type sumologic
307
+
308
+ # New
309
+ @type sumologic_radiant
310
+
311
+ # ... rest of configuration remains the same
312
+ </match>
313
+ ```
314
+
315
+ 3. **Verify Ruby version**: Ensure you're running Ruby 3.0 or newer.
316
+
317
+ ### Breaking Changes
318
+
319
+ - **Ruby 2.x is no longer supported** - Ruby 3.0+ is required
320
+ - **TLS 1.0/1.1 disabled by default** - TLS 1.2+ is enforced
321
+ - **Dependency changes**: Uses `oj` instead of `yajl`, `net-http-persistent` instead of `httpclient`
322
+
323
+ ## Fixed Issues from Original Plugin
324
+
325
+ This modernized version fixes several issues reported in the original plugin:
326
+
327
+ ### Issue #85: Missing log_key Warning
328
+ **Problem**: When using `log_format=text` without the correct `log_key`, logs would silently stop being sent.
329
+
330
+ **Fix**: Added comprehensive warnings at both startup and runtime:
331
+ - Startup warning when `log_format` is set to `text` or `fields`
332
+ - Runtime warning showing available record keys when `log_key` is missing
333
+ - Enhanced debug logging to track processed vs. dropped records
334
+
335
+ ### Issue #83: Cookie Handling Warnings
336
+ **Problem**: The original plugin using `httpclient` would spam logs with "Unknown key: MAX-AGE" and "Unknown key: SameSite" warnings.
337
+
338
+ **Fix**: Replaced `httpclient` with `net-http-persistent`, which handles modern cookie attributes properly and eliminates these noisy warnings entirely.
339
+
340
+ ### Issue #38: Custom SSL Certificates
341
+ **Problem**: No support for custom CA certificates or client certificate authentication.
342
+
343
+ **Fix**: Added full SSL/TLS customization:
344
+ - `ca_file` - Custom CA certificate file
345
+ - `ca_path` - Custom CA certificate directory
346
+ - `client_cert` / `client_key` - Mutual TLS support
347
+
348
+ These options allow secure connections with internal PKI, self-signed certificates, or enterprise certificate requirements.
349
+
350
+ ### Enhanced Debugging
351
+ Added detailed debug logging throughout the plugin:
352
+ - Chunk processing statistics (processed, dropped, sent counts)
353
+ - SSL configuration details
354
+ - Connection initialization messages
355
+ - Per-batch send tracking with retry information
356
+
357
+ ## Log Formats
358
+
359
+ ### `text` Format
360
+ Sends the entire record as plain text.
361
+
362
+ ### `json` Format (Default)
363
+ Sends the record as JSON:
364
+ ```json
365
+ {"field1": "value1", "field2": "value2"}
366
+ ```
367
+
368
+ ### `json_merge` Format
369
+ Merges a specific field with the record:
370
+ ```xml
371
+ <match **>
372
+ @type sumologic_radiant
373
+ log_format json_merge
374
+ log_key log
375
+ </match>
376
+ ```
377
+
378
+ ### `fields` Format
379
+ Extracts a specific field as the message:
380
+ ```xml
381
+ <match **>
382
+ @type sumologic_radiant
383
+ log_format fields
384
+ log_key message
385
+ </match>
386
+ ```
387
+
388
+ ## Development
389
+
390
+ ### Prerequisites
391
+
392
+ - Ruby 3.0 or newer
393
+ - Bundler 2.0+
394
+ - Git
395
+
396
+ ### Setup
397
+
398
+ ```bash
399
+ git clone https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant.git
400
+ cd fluent-plugin-sumologic-radiant
401
+ bundle install
402
+ ```
403
+
404
+ ### Running Tests
405
+
406
+ ```bash
407
+ bundle exec rspec
408
+ ```
409
+
410
+ ### Linting
411
+
412
+ ```bash
413
+ bundle exec rubocop
414
+ ```
415
+
416
+ ### Building the Gem
417
+
418
+ ```bash
419
+ bundle exec rake build
420
+ ```
421
+
422
+ The gem will be created in the `pkg/` directory.
423
+
424
+ ## Contributing
425
+
426
+ Contributions are welcome! Please:
427
+
428
+ 1. Fork the repository
429
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
430
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
431
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
432
+ 5. Open a Pull Request
433
+
434
+ Please ensure:
435
+ - Tests pass (`bundle exec rspec`)
436
+ - Code passes linting (`bundle exec rubocop`)
437
+ - New features include tests
438
+ - Documentation is updated
439
+
440
+ ## License
441
+
442
+ Copyright 2025 G. Rahul Nutakki
443
+ Copyright 2016-2024 Sumo Logic Inc.
444
+
445
+ Licensed under the Apache License, Version 2.0 (the "License");
446
+ you may not use this file except in compliance with the License.
447
+ You may obtain a copy of the License at
448
+
449
+ http://www.apache.org/licenses/LICENSE-2.0
450
+
451
+ Unless required by applicable law or agreed to in writing, software
452
+ distributed under the License is distributed on an "AS IS" BASIS,
453
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
454
+ See the License for the specific language governing permissions and
455
+ limitations under the License.
456
+
457
+ ## Attribution
458
+
459
+ This project is a derivative work of [fluent-plugin-sumologic_output](https://github.com/SumoLogic/fluentd-output-sumologic) by Sumo Logic Inc. See [NOTICE](NOTICE) for full attribution details.
460
+
461
+ ## Support
462
+
463
+ - **Issues**: [GitHub Issues](https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/issues)
464
+ - **Documentation**: [README.md](https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/blob/main/README.md)
465
+ - **Original Plugin**: [fluent-plugin-sumologic_output](https://github.com/SumoLogic/fluentd-output-sumologic)
466
+
467
+ ## Changelog
468
+
469
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[rubocop spec]
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/fluent/plugin/sumologic_radiant/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-sumologic-radiant"
7
+ spec.version = Fluent::Plugin::SumologicRadiant::VERSION
8
+ spec.authors = ["G. Rahul Nutakki"]
9
+ spec.email = ["gnanirn@gmail.com"]
10
+
11
+ spec.summary = "Modernized Fluentd output plugin for Sumo Logic"
12
+ spec.description = "A modernized and actively maintained Fluentd output plugin for " \
13
+ "Sumo Logic HTTP Collector with updated dependencies, " \
14
+ "improved performance, and Ruby 3.x support. Forked from the " \
15
+ "original Sumo Logic plugin with enhancements and security fixes."
16
+ spec.homepage = "https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant"
17
+ spec.license = "Apache-2.0"
18
+ spec.required_ruby_version = ">= 3.0.0"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = "https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant"
22
+ spec.metadata["changelog_uri"] = "https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/blob/main/CHANGELOG.md"
23
+ spec.metadata["bug_tracker_uri"] = "https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/issues"
24
+ spec.metadata["documentation_uri"] = "https://github.com/gnanirahulnutakki/fluent-plugin-sumologic-radiant/blob/main/README.md"
25
+ spec.metadata["rubygems_mfa_required"] = "true"
26
+
27
+ # Specify which files should be added to the gem when it is released.
28
+ spec.files = Dir.glob("lib/**/*") + %w[
29
+ README.md
30
+ LICENSE
31
+ NOTICE
32
+ fluent-plugin-sumologic-radiant.gemspec
33
+ Gemfile
34
+ Rakefile
35
+ ]
36
+ spec.require_paths = ["lib"]
37
+
38
+ # Runtime dependencies - modernized versions
39
+ spec.add_dependency "fluentd", ">= 1.16", "< 2.0"
40
+ spec.add_dependency "net-http-persistent", ">= 4.0", "< 6.0"
41
+ spec.add_dependency "oj", "~> 3.16"
42
+
43
+ # Development dependencies
44
+ spec.add_development_dependency "bundler", ">= 2.0"
45
+ spec.add_development_dependency "rake", "~> 13.0"
46
+ spec.add_development_dependency "rspec", "~> 3.13"
47
+ spec.add_development_dependency "rubocop", "~> 1.60"
48
+ spec.add_development_dependency "rubocop-rspec", "~> 3.0"
49
+ spec.add_development_dependency "simplecov", "~> 0.22"
50
+ spec.add_development_dependency "test-unit", "~> 3.6"
51
+ spec.add_development_dependency "webmock", "~> 3.23"
52
+ end