fluent-plugin-sumologic_output 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 43bb5af71751e54c3c4e2efea36eaebbd7a5e56a1528608003e8bbe93833a3d5
4
+ data.tar.gz: fe90ef66f1c5761c3542fefa962ecede5cc40b4d5ea6f5fdb5cd1d7ef2c4a786
5
+ SHA512:
6
+ metadata.gz: d6e6f301db7a74a102d4385d6a24821fa1e918f2be2d45cb177c69c0e4390e0c2d638ab567c9eb1d81d378181204f132cc0bc1681cc6e4c581e1d31cafebcd03
7
+ data.tar.gz: 6410a9714c3000e0a976713885af890cf7f9f4b682eefe46414bc83379c74faeeb36f3e783c8e999aa9121d024517c36941c266cde3c210bb1ca8a29a28bfd83
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ *.rbc
3
+ Gemfile.lock
4
+ .idea/
5
+ TAGS
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ lang: ruby
2
+ before_install: gem install bundler
3
+ script: ci/build.sh
4
+ deploy:
5
+ provider: rubygems
6
+ api_key:
7
+ secure: mzu7CaM8x5BLZ2QvgQJFfY/xvzZN2+gpMieRoBnmefjhhs+zGjqzBn9wN+4/IZNQUKhDE729CEx1xSEegz44Ru73sNEsS4Y/jLNqr24Swcr4xyYcqxX58x18o1K28HD1Mp9NhS8gLIkd/sucCcSAHPag6Zkk00gETGsGCXFHxYP5HpXbBMKy1OFZ3o7dGv+Hv4g5XtDaM1Kjwcku398PsQsBmh0jJyag+NL804dUL66weTA3P7q94/TEVZ1lbvUZlokzxHBhkO0eHM2fuCdKzW1BneePxYnMRFzjRxXcYoalfEVoy9KHi3mDBCtj4Bw6hSgfnrDFVjZzoMPybOLJDt9DlYEplcWlXlS3EuDr5aYgyfkUbuv1OZm/94EdkMa4epH51vq0r6AHstG7ZCmrBxiLUMs0wgwRSPTIK1hJG+UFuCxGASU+IH8OD8bTav21cXEhVLDw5dEzk6smnfY+mpAexiW5ytIc9wf0qkP6bbICH9zRHYUWHxcCTqouhArHPyyESSngAYkpdHbRql+uGll8ab6IaVp33WvKqYQK2QnTcb1A7pgtiAxzhl0yBTR/oNIRdj6X6y7FmRuaEmkU29jzuetcq4xdgQTkNfbeLITwyRn2hJBGHIEcvHPwilzZGIfr96QcqBw/AGrcIirkD3NuZ86DJZ8Ucn3BbKXEmTU=
8
+ gem: fluent-plugin-sumologic_output
9
+ on:
10
+ tags: true
11
+ repo: SumoLogic/fluentd-output-sumologic
data/CHANGELOG.md ADDED
@@ -0,0 +1,85 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file. Tracking did not begin until version 1.10.
4
+
5
+ <a name="1.4.0"></a>
6
+ # [1.4.0] (2019-01-16)
7
+
8
+ * [Add timestamp_key, prefer log message when merging](https://github.com/SumoLogic/fluentd-output-sumologic/pull/37)
9
+
10
+ <a name="1.3.2"></a>
11
+ # [1.3.2] (2018-12-05)
12
+
13
+ * Fix verify SSL bug
14
+
15
+ <a name="1.3.1"></a>
16
+ # [1.3.1] (2018-08-30)
17
+
18
+ * [Sumo Logic endpoint is a secret](https://github.com/SumoLogic/fluentd-output-sumologic/pull/32)
19
+
20
+ <a name="1.3.0"></a>
21
+ # [1.3.0] (2018-08-08)
22
+
23
+ <a name="1.2.0"></a>
24
+ # [1.2.0] (2018-07-18)
25
+
26
+ * add support for multi worker
27
+
28
+ <a name="1.1.1"></a>
29
+ # [1.1.1] (2018-07-12)
30
+
31
+ * if `record[@log_key]` is json, parse it as JSON and not as string.
32
+
33
+ <a name="1.1.0"></a>
34
+ # [1.1.0] (2018-06-29)
35
+
36
+ * Add support for sending metrics.
37
+
38
+ <a name="1.0.3"></a>
39
+ # [1.0.3] (2018-05-07)
40
+
41
+ * [Fix #26 -- Don't chomp if the message is not chomp-able](https://github.com/SumoLogic/fluentd-output-sumologic/pull/29)
42
+
43
+ <a name="1.0.2"></a>
44
+ # [1.0.2] (2018-04-09)
45
+
46
+ * [add option to turn off adding timestamp to logs](https://github.com/SumoLogic/fluentd-output-sumologic/pull/27)
47
+
48
+ <a name="1.0.1"></a>
49
+ # [1.0.1] (2017-12-19)
50
+
51
+ * [Add client header for fluentd output](https://github.com/SumoLogic/fluentd-output-sumologic/pull/22)
52
+
53
+ <a name="1.0.0"></a>
54
+ # [1.0.0] (2017-11-06)
55
+
56
+ * [Upgrade to 0.14 API, send with ms precision](https://github.com/SumoLogic/fluentd-output-sumologic/pull/12)
57
+ * [Switch to httpclient](https://github.com/SumoLogic/fluentd-output-sumologic/pull/16)
58
+ * [Fix missing variable and improve config example](https://github.com/SumoLogic/fluentd-output-sumologic/pull/17)
59
+
60
+ <a name="0.0.7"></a>
61
+ # [0.0.7] (2017-10-26)
62
+
63
+ * [Expand parameters in the output configuration](https://github.com/SumoLogic/fluentd-output-sumologic/pull/14)
64
+ * [add open_timeout option](https://github.com/SumoLogic/fluentd-output-sumologic/pull/15)
65
+
66
+ <a name="0.0.6"></a>
67
+ # [0.0.6] (2017-08-23)
68
+
69
+ * Fix 0.0.5
70
+
71
+ <a name="0.0.5"></a>
72
+ # [0.0.5] (2017-08-18)
73
+
74
+ * [Ignore garbage records. Fix inspired by other plugins](https://github.com/SumoLogic/fluentd-output-sumologic/pull/7)
75
+ * [Extract the source_name from FluentD's buffer](https://github.com/SumoLogic/fluentd-output-sumologic/pull/8)
76
+
77
+ <a name="0.0.4"></a>
78
+ # [0.0.4] (2017-07-05)
79
+
80
+ * [Raise an exception for all non HTTP Success response codes](https://github.com/SumoLogic/fluentd-output-sumologic/pull/5)
81
+
82
+ <a name="0.0.3"></a>
83
+ # [0.0.3] (2016-12-10)
84
+
85
+ * Initial Release
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'codecov'
5
+ gem 'simplecov'
6
+ gem 'webmock'
7
+ end
8
+
9
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,138 @@
1
+ [![Build Status](https://travis-ci.org/SumoLogic/fluentd-output-sumologic.svg?branch=master)](https://travis-ci.org/SumoLogic/fluentd-output-sumologic) [![Gem Version](https://badge.fury.io/rb/fluent-plugin-sumologic_output.svg)](https://badge.fury.io/rb/fluent-plugin-sumologic_output) ![](https://ruby-gem-downloads-badge.herokuapp.com/fluent-plugin-sumologic_output?type=total) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/SumoLogic/fluentd-output-sumologic/issues)
2
+
3
+ # fluent-plugin-sumologic_output, a plugin for [Fluentd](http://fluentd.org)
4
+
5
+ This plugin has been designed to output logs or metrics to [SumoLogic](http://www.sumologic.com) via a [HTTP collector endpoint](http://help.sumologic.com/Send_Data/Sources/02Sources_for_Hosted_Collectors/HTTP_Source)
6
+
7
+ ## Support
8
+ The code in this repository has been developed in collaboration with the Sumo Logic community and is not supported via standard Sumo Logic Support channels. For any issues or questions please submit an issue within the GitHub repository. The maintainers of this project will work directly with the community to answer any questions, address bugs, or review any requests for new features.
9
+
10
+ ## License
11
+ Released under Apache 2.0 License.
12
+
13
+ ## Installation
14
+
15
+ gem install fluent-plugin-sumologic_output
16
+
17
+ ## Configuration
18
+
19
+ Configuration options for fluent.conf are:
20
+
21
+ * `data_type` - The type of data that will be sent to Sumo Logic, either `logs` or `metrics` (Default is `logs `)
22
+ * `endpoint` - SumoLogic HTTP Collector URL
23
+ * `verify_ssl` - Verify ssl certificate. (default is `true`)
24
+ * `source_category` - Set _sourceCategory metadata field within SumoLogic (default is `nil`)
25
+ * `source_name` - Set _sourceName metadata field within SumoLogic - overrides source_name_key (default is `nil`)
26
+ * `source_name_key` - Set as source::path_key's value so that the source_name can be extracted from Fluentd's buffer (default `source_name`)
27
+ * `source_host` - Set _sourceHost metadata field within SumoLogic (default is `nil`)
28
+ * `log_format` - Format to post logs into Sumo. (default `json`)
29
+ * text - Logs will appear in SumoLogic in text format (taken from the field specified in `log_key`)
30
+ * json - Logs will appear in SumoLogic in json format.
31
+ * json_merge - Same as json but merge content of `log_key` into the top level and strip `log_key`
32
+ * `log_key` - Used to specify the key when merging json or sending logs in text format (default `message`)
33
+ * `open_timeout` - Set timeout seconds to wait until connection is opened.
34
+ * `add_timestamp` - Add `timestamp` (or `timestamp_key`) field to logs before sending to sumologic (default `true`)
35
+ * `timestamp_key` - Field name when `add_timestamp` is on (default `timestamp`)
36
+ * `proxy_uri` - Add the `uri` of the `proxy` environment if present.
37
+ * `metric_data_format` - The format of metrics you will be sending, either `graphite` or `carbon2` or `prometheus` (Default is `graphite `)
38
+ * `disable_cookies` - Option to disable cookies on the HTTP Client. (Default is `false `)
39
+
40
+ ### Example Configuration
41
+ Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
42
+ ```
43
+ <source>
44
+ @type tail
45
+ format json
46
+ time_key time
47
+ path /path/to/*.log
48
+ pos_file /path/to/pos/ggcp-app.log.pos
49
+ time_format %Y-%m-%dT%H:%M:%S.%NZ
50
+ tag appa.*
51
+ read_from_head false
52
+ </source>
53
+
54
+ <match appa.**>
55
+ @type sumologic
56
+ endpoint https://collectors.sumologic.com/receiver/v1/http/XXXXXXXXXX
57
+ log_format json
58
+ source_category prod/someapp/logs
59
+ source_name AppA
60
+ open_timeout 10
61
+ </match>
62
+ ```
63
+
64
+ Sending metrics to Sumo Logic using `in_http`:
65
+ ```
66
+ <source>
67
+ @type http
68
+ port 8888
69
+ bind 0.0.0.0
70
+ </source>
71
+
72
+ <match test.carbon2>
73
+ @type sumologic
74
+ endpoint https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/ZaVnC4dhaV1hYfCAiqSH-PDY6gUOIgZvO60U_-y8SPQfK0Ks-ht7owrbk1AkX_ACp0uUxuLZOCw5QjBg1ndVPZ5TOJCFgNGRtFDoTDuQ2hzs3sn6FlfBSw==
75
+ data_type metrics
76
+ metric_data_format carbon2
77
+ flush_interval 1s
78
+ </match>
79
+
80
+ <match test.graphite>
81
+ @type sumologic
82
+ endpoint https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/ZaVnC4dhaV1hYfCAiqSH-PDY6gUOIgZvO60U_-y8SPQfK0Ks-ht7owrbk1AkX_ACp0uUxuLZOCw5QjBg1ndVPZ5TOJCFgNGRtFDoTDuQ2hzs3sn6FlfBSw==
83
+ data_type metrics
84
+ metric_data_format graphite
85
+ flush_interval 1s
86
+ </match>
87
+ ```
88
+
89
+ ## Example input/output
90
+
91
+ Assuming following inputs are coming from a log file named `/var/log/appa_webserver.log`
92
+ ```
93
+ {"asctime": "2016-12-10 03:56:35+0000", "levelname": "INFO", "name": "appa", "funcName": "do_something", "lineno": 29, "message": "processing something", "source_ip": "123.123.123.123"}
94
+ ```
95
+
96
+ Then output becomes as below within SumoLogic
97
+ ```
98
+ {
99
+ "timestamp":1481343785000,
100
+ "asctime":"2016-12-10 03:56:35+0000",
101
+ "levelname":"INFO",
102
+ "name":"appa",
103
+ "funcName":"do_something",
104
+ "lineno":29,
105
+ "message":"processing something",
106
+ "source_ip":"123.123.123.123"
107
+ }
108
+ ```
109
+
110
+ ## Dynamic Configuration within log message
111
+
112
+ The plugin supports overriding SumoLogic metadata and log_format parameters within each log message by attaching the field `_sumo_metadata` to the log message.
113
+
114
+ NOTE: The `_sumo_metadata` field will be stripped before posting to SumoLogic.
115
+
116
+ Example
117
+
118
+ ```
119
+ {
120
+ "name": "appa",
121
+ "source_ip": "123.123.123.123",
122
+ "funcName": "do_something",
123
+ "lineno": 29,
124
+ "asctime": "2016-12-10 03:56:35+0000",
125
+ "message": "processing something",
126
+ "_sumo_metadata": {
127
+ "category": "new_sourceCategory",
128
+ "source": "override_sourceName",
129
+ "host": "new_sourceHost",
130
+ "log_format": "merge_json_log"
131
+ },
132
+ "levelname": "INFO"
133
+ }
134
+ ```
135
+
136
+ ### TLS 1.2 Requirement
137
+
138
+ Sumo Logic only accepts connections from clients using TLS version 1.2 or greater. To utilize the content of this repo, ensure that it's running in an execution environment that is configured to use TLS 1.2 or greater.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ test.warning = false
9
+ end
10
+
11
+ task :default => :test
data/ci/build.sh ADDED
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ echo "Starting build process in: `pwd`"
4
+ set -e
5
+
6
+ if [! -z "${TRAVIS_TAG}" ]; then
7
+ echo "Building for tag ${TRAVIS_TAG}, modify .gemspec file..."
8
+ sed -i '' "s/0.0.0/${TRAVIS_TAG}/g" ./fluent-plugin-sumologic_output.gemspec
9
+ fi
10
+
11
+ echo "Install bundler..."
12
+ bundle install
13
+
14
+ echo "Run unit tests..."
15
+ bundle exec rake
16
+
17
+ echo "DONE"
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "fluent-plugin-sumologic_output"
7
+ gem.version = "0.0.0"
8
+ gem.authors = ["Steven Adams", "Frank Reno"]
9
+ gem.email = ["stevezau@gmail.com", "frank.reno@me.com"]
10
+ gem.description = %q{Output plugin to SumoLogic HTTP Endpoint}
11
+ gem.summary = %q{Output plugin to SumoLogic HTTP Endpoint}
12
+ gem.homepage = "https://github.com/SumoLogic/fluentd-output-sumologic"
13
+ gem.license = "Apache-2.0"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.required_ruby_version = '>= 2.0.0'
21
+
22
+ gem.add_development_dependency "bundler", "~> 2"
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency 'test-unit', '~> 3.1.0'
25
+ gem.add_development_dependency "codecov", ">= 0.1.10"
26
+ gem.add_runtime_dependency "fluentd", ">= 0.14.12"
27
+ gem.add_runtime_dependency 'httpclient', '~> 2.8.0'
28
+ end
@@ -0,0 +1,269 @@
1
+ require 'fluent/plugin/output'
2
+ require 'net/https'
3
+ require 'yajl'
4
+ require 'httpclient'
5
+
6
+ class SumologicConnection
7
+
8
+ attr_reader :http
9
+
10
+ def initialize(endpoint, verify_ssl, connect_timeout, proxy_uri, disable_cookies)
11
+ @endpoint = endpoint
12
+ create_http_client(verify_ssl, connect_timeout, proxy_uri, disable_cookies)
13
+ end
14
+
15
+ def publish(raw_data, source_host=nil, source_category=nil, source_name=nil, data_type, metric_data_type)
16
+ response = http.post(@endpoint, raw_data, request_headers(source_host, source_category, source_name, data_type, metric_data_type))
17
+ unless response.ok?
18
+ raise RuntimeError, "Failed to send data to HTTP Source. #{response.code} - #{response.body}"
19
+ end
20
+ end
21
+
22
+ def request_headers(source_host, source_category, source_name, data_type, metric_data_format)
23
+ headers = {
24
+ 'X-Sumo-Name' => source_name,
25
+ 'X-Sumo-Category' => source_category,
26
+ 'X-Sumo-Host' => source_host,
27
+ 'X-Sumo-Client' => 'fluentd-output'
28
+ }
29
+ if data_type == 'metrics'
30
+ case metric_data_format
31
+ when 'graphite'
32
+ headers['Content-Type'] = 'application/vnd.sumologic.graphite'
33
+ when 'carbon2'
34
+ headers['Content-Type'] = 'application/vnd.sumologic.carbon2'
35
+ when 'prometheus'
36
+ headers['Content-Type'] = 'application/vnd.sumologic.prometheus'
37
+ else
38
+ raise RuntimeError, "Invalid #{metric_data_format}, must be graphite or carbon2 or prometheus"
39
+ end
40
+ end
41
+ return headers
42
+ end
43
+
44
+ def ssl_options(verify_ssl)
45
+ verify_ssl==true ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
46
+ end
47
+
48
+ def create_http_client(verify_ssl, connect_timeout, proxy_uri, disable_cookies)
49
+ @http = HTTPClient.new(proxy_uri)
50
+ @http.ssl_config.verify_mode = ssl_options(verify_ssl)
51
+ @http.connect_timeout = connect_timeout
52
+ if disable_cookies
53
+ @http.cookie_manager = nil
54
+ end
55
+ end
56
+ end
57
+
58
+ class Fluent::Plugin::Sumologic < Fluent::Plugin::Output
59
+ # First, register the plugin. NAME is the name of this plugin
60
+ # and identifies the plugin in the configuration file.
61
+ Fluent::Plugin.register_output('sumologic', self)
62
+
63
+ helpers :compat_parameters
64
+ DEFAULT_BUFFER_TYPE = "memory"
65
+ LOGS_DATA_TYPE = "logs"
66
+ METRICS_DATA_TYPE = "metrics"
67
+ DEFAULT_DATA_TYPE = LOGS_DATA_TYPE
68
+ DEFAULT_METRIC_FORMAT_TYPE = 'graphite'
69
+
70
+ config_param :data_type, :string, :default => DEFAULT_DATA_TYPE
71
+ config_param :metric_data_format, :default => DEFAULT_METRIC_FORMAT_TYPE
72
+ config_param :endpoint, :string, secret: true
73
+ config_param :log_format, :string, :default => 'json'
74
+ config_param :log_key, :string, :default => 'message'
75
+ config_param :source_category, :string, :default => nil
76
+ config_param :source_name, :string, :default => nil
77
+ config_param :source_name_key, :string, :default => 'source_name'
78
+ config_param :source_host, :string, :default => nil
79
+ config_param :verify_ssl, :bool, :default => true
80
+ config_param :delimiter, :string, :default => "."
81
+ config_param :open_timeout, :integer, :default => 60
82
+ config_param :add_timestamp, :bool, :default => true
83
+ config_param :timestamp_key, :string, :default => 'timestamp'
84
+ config_param :proxy_uri, :string, :default => nil
85
+ config_param :disable_cookies, :bool, :default => false
86
+
87
+ config_section :buffer do
88
+ config_set_default :@type, DEFAULT_BUFFER_TYPE
89
+ config_set_default :chunk_keys, ['tag']
90
+ end
91
+
92
+ def initialize
93
+ super
94
+ end
95
+
96
+ def multi_workers_ready?
97
+ true
98
+ end
99
+
100
+ # This method is called before starting.
101
+ def configure(conf)
102
+
103
+ compat_parameters_convert(conf, :buffer)
104
+
105
+ unless conf['endpoint'] =~ URI::regexp
106
+ raise Fluent::ConfigError, "Invalid SumoLogic endpoint url: #{conf['endpoint']}"
107
+ end
108
+
109
+ unless conf['data_type'].nil?
110
+ unless conf['data_type'] =~ /\A(?:logs|metrics)\z/
111
+ raise Fluent::ConfigError, "Invalid data_type #{conf['data_type']} must be logs or metrics"
112
+ end
113
+ end
114
+
115
+ if conf['data_type'].nil? || conf['data_type'] == LOGS_DATA_TYPE
116
+ unless conf['log_format'].nil?
117
+ unless conf['log_format'] =~ /\A(?:json|text|json_merge)\z/
118
+ raise Fluent::ConfigError, "Invalid log_format #{conf['log_format']} must be text, json or json_merge"
119
+ end
120
+ end
121
+ end
122
+
123
+ if conf['data_type'] == METRICS_DATA_TYPE && ! conf['metrics_data_type'].nil?
124
+ unless conf['metrics_data_type'] =~ /\A(?:graphite|carbon2|pronetheus)\z/
125
+ raise Fluent::ConfigError, "Invalid metrics_data_type #{conf['metrics_data_type']} must be graphite or carbon2 or prometheus"
126
+ end
127
+ end
128
+
129
+ @sumo_conn = SumologicConnection.new(conf['endpoint'], conf['verify_ssl'], conf['open_timeout'].to_i, conf['proxy_uri'], conf['disable_cookies'])
130
+ super
131
+ end
132
+
133
+ # This method is called when starting.
134
+ def start
135
+ super
136
+ end
137
+
138
+ # This method is called when shutting down.
139
+ def shutdown
140
+ super
141
+ end
142
+
143
+ # Used to merge log record into top level json
144
+ def merge_json(record)
145
+ if record.has_key?(@log_key)
146
+ log = record[@log_key].strip
147
+ if log[0].eql?('{') && log[-1].eql?('}')
148
+ begin
149
+ record = record.merge(JSON.parse(log))
150
+ record.delete(@log_key)
151
+ rescue JSON::ParserError
152
+ # do nothing, ignore
153
+ end
154
+ end
155
+ end
156
+ record
157
+ end
158
+
159
+ # Strip sumo_metadata and dump to json
160
+ def dump_log(log)
161
+ log.delete('_sumo_metadata')
162
+ begin
163
+ parser = Yajl::Parser.new
164
+ hash = parser.parse(log[@log_key])
165
+ log[@log_key] = hash
166
+ Yajl.dump(log)
167
+ rescue
168
+ Yajl.dump(log)
169
+ end
170
+ end
171
+
172
+ def format(tag, time, record)
173
+ if defined? time.nsec
174
+ mstime = time * 1000 + (time.nsec / 1000000)
175
+ [mstime, record].to_msgpack
176
+ else
177
+ [time, record].to_msgpack
178
+ end
179
+ end
180
+
181
+ def formatted_to_msgpack_binary
182
+ true
183
+ end
184
+
185
+ def sumo_key(sumo_metadata, chunk)
186
+ source_name = sumo_metadata['source'] || @source_name
187
+ source_name = extract_placeholders(source_name, chunk) unless source_name.nil?
188
+
189
+ source_category = sumo_metadata['category'] || @source_category
190
+ source_category = extract_placeholders(source_category, chunk) unless source_category.nil?
191
+
192
+ source_host = sumo_metadata['host'] || @source_host
193
+ source_host = extract_placeholders(source_host, chunk) unless source_host.nil?
194
+
195
+ "#{source_name}:#{source_category}:#{source_host}"
196
+ end
197
+
198
+ # Convert timestamp to 13 digit epoch if necessary
199
+ def sumo_timestamp(time)
200
+ time.to_s.length == 13 ? time : time * 1000
201
+ end
202
+
203
+ # This method is called every flush interval. Write the buffer chunk
204
+ def write(chunk)
205
+ messages_list = {}
206
+
207
+ # Sort messages
208
+ chunk.msgpack_each do |time, record|
209
+ # plugin dies randomly
210
+ # https://github.com/uken/fluent-plugin-elasticsearch/commit/8597b5d1faf34dd1f1523bfec45852d380b26601#diff-ae62a005780cc730c558e3e4f47cc544R94
211
+ next unless record.is_a? Hash
212
+ sumo_metadata = record.fetch('_sumo_metadata', {:source => record[@source_name_key] })
213
+ key = sumo_key(sumo_metadata, chunk)
214
+ log_format = sumo_metadata['log_format'] || @log_format
215
+
216
+ # Strip any unwanted newlines
217
+ record[@log_key].chomp! if record[@log_key] && record[@log_key].respond_to?(:chomp!)
218
+
219
+ case @data_type
220
+ when 'logs'
221
+ case log_format
222
+ when 'text'
223
+ log = record[@log_key]
224
+ unless log.nil?
225
+ log.strip!
226
+ end
227
+ when 'json_merge'
228
+ if @add_timestamp
229
+ record = { @timestamp_key => sumo_timestamp(time) }.merge(record)
230
+ end
231
+ log = dump_log(merge_json(record))
232
+ else
233
+ if @add_timestamp
234
+ record = { @timestamp_key => sumo_timestamp(time) }.merge(record)
235
+ end
236
+ log = dump_log(record)
237
+ end
238
+ when 'metrics'
239
+ log = record[@log_key]
240
+ unless log.nil?
241
+ log.strip!
242
+ end
243
+ end
244
+
245
+ unless log.nil?
246
+ if messages_list.key?(key)
247
+ messages_list[key].push(log)
248
+ else
249
+ messages_list[key] = [log]
250
+ end
251
+ end
252
+
253
+ end
254
+
255
+ # Push logs to sumo
256
+ messages_list.each do |key, messages|
257
+ source_name, source_category, source_host = key.split(':')
258
+ @sumo_conn.publish(
259
+ messages.join("\n"),
260
+ source_host =source_host,
261
+ source_category =source_category,
262
+ source_name =source_name,
263
+ data_type =@data_type,
264
+ metric_data_format =@metric_data_format
265
+ )
266
+ end
267
+
268
+ end
269
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ if ENV['CI'] == 'true'
5
+ require 'codecov'
6
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
7
+ end
8
+
9
+ $LOAD_PATH.unshift(File.expand_path("../../", __FILE__))
10
+ require "test-unit"
11
+ require "fluent/test"
12
+ require "fluent/test/driver/output"
13
+ require "fluent/test/helpers"
14
+
15
+ Test::Unit::TestCase.include(Fluent::Test::Helpers)
16
+ Test::Unit::TestCase.extend(Fluent::Test::Helpers)
@@ -0,0 +1,330 @@
1
+ require "test-unit"
2
+ require "fluent/test"
3
+ require "fluent/test/driver/output"
4
+ require "fluent/test/helpers"
5
+ require 'webmock/test_unit'
6
+ require 'fluent/plugin/out_sumologic'
7
+
8
+ class SumologicOutput < Test::Unit::TestCase
9
+ include Fluent::Test::Helpers
10
+
11
+ def setup
12
+ Fluent::Test.setup
13
+ end
14
+
15
+ def create_driver(conf = CONFIG)
16
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::Sumologic).configure(conf)
17
+ end
18
+
19
+ def test_no_endpoint_configure
20
+ config = %{}
21
+ exception = assert_raise(Fluent::ConfigError) {create_driver(config)}
22
+ assert_equal("Invalid SumoLogic endpoint url: ", exception.message)
23
+ end
24
+
25
+ def test_invalid_data_type_configure
26
+ config = %{
27
+ endpoint https://SUMOLOGIC_URL
28
+ data_type 'foo'
29
+ }
30
+ exception = assert_raise(Fluent::ConfigError) {create_driver(config)}
31
+ assert_equal("Invalid data_type foo must be logs or metrics", exception.message)
32
+ end
33
+
34
+ def test_invalid_log_format_configure
35
+ config = %{
36
+ endpoint https://SUMOLOGIC_URL
37
+ log_format foo
38
+ }
39
+ exception = assert_raise(Fluent::ConfigError) {create_driver(config)}
40
+ assert_equal("Invalid log_format foo must be text, json or json_merge", exception.message)
41
+ end
42
+
43
+ def test_invalid_metrics_data_type
44
+ config = %{
45
+ endpoint https://SUMOLOGIC_URL
46
+ data_type metrics
47
+ metrics_data_type foo
48
+ }
49
+ exception = assert_raise(Fluent::ConfigError) {create_driver(config)}
50
+ assert_equal("Invalid metrics_data_type foo must be graphite or carbon2 or prometheus", exception.message)
51
+ end
52
+
53
+ def test_default_configure
54
+ config = %{
55
+ endpoint https://SUMOLOGIC_URL
56
+ }
57
+ instance = create_driver(config).instance
58
+
59
+ assert_equal instance.data_type, 'logs'
60
+ assert_equal instance.metric_data_format, 'graphite'
61
+ assert_equal instance.endpoint, 'https://SUMOLOGIC_URL'
62
+ assert_equal instance.log_format, 'json'
63
+ assert_equal instance.log_key, 'message'
64
+ assert_equal instance.source_category, nil
65
+ assert_equal instance.source_name, nil
66
+ assert_equal instance.source_name_key, 'source_name'
67
+ assert_equal instance.source_host, nil
68
+ assert_equal instance.verify_ssl, true
69
+ assert_equal instance.delimiter, '.'
70
+ assert_equal instance.open_timeout, 60
71
+ assert_equal instance.add_timestamp, true
72
+ assert_equal instance.timestamp_key, 'timestamp'
73
+ assert_equal instance.proxy_uri, nil
74
+ assert_equal instance.disable_cookies, false
75
+ end
76
+
77
+ def test_emit_text
78
+ config = %{
79
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
80
+ log_format text
81
+ source_category test
82
+ source_host test
83
+ source_name test
84
+
85
+ }
86
+ driver = create_driver(config)
87
+ time = event_time
88
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
89
+ driver.run do
90
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => 'test'})
91
+ end
92
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
93
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
94
+ body: "test",
95
+ times:1
96
+ end
97
+
98
+ def test_emit_json
99
+ config = %{
100
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
101
+ log_format json
102
+ source_category test
103
+ source_host test
104
+ source_name test
105
+
106
+ }
107
+ driver = create_driver(config)
108
+ time = event_time
109
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
110
+ driver.run do
111
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => 'test'})
112
+ end
113
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
114
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
115
+ body: /\A{"timestamp":\d+.,"foo":"bar","message":"test"}\z/,
116
+ times:1
117
+ end
118
+
119
+ def test_emit_json_double_encoded
120
+ config = %{
121
+ endpoint https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234
122
+ log_format json
123
+ source_category test
124
+ source_host test
125
+ source_name test
126
+
127
+ }
128
+ driver = create_driver(config)
129
+ time = event_time
130
+ stub_request(:post, 'https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234')
131
+ driver.run do
132
+ driver.feed("output.test", time, {'message' => '{"bar":"foo"}'})
133
+ end
134
+ assert_requested :post, "https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234",
135
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
136
+ body: /\A{"timestamp":\d+.,"message":{"bar":"foo"}}\z/,
137
+ times:1
138
+ end
139
+
140
+ def test_emit_text_format_as_json
141
+ config = %{
142
+ endpoint https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234
143
+ log_format json
144
+ source_category test
145
+ source_host test
146
+ source_name test
147
+
148
+ }
149
+ driver = create_driver(config)
150
+ time = event_time
151
+ stub_request(:post, 'https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234')
152
+ driver.run do
153
+ driver.feed("output.test", time, {'message' => 'some message'})
154
+ end
155
+ assert_requested :post, "https://endpoint3.collection.us2.sumologic.com/receiver/v1/http/1234",
156
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
157
+ body: /\A{"timestamp":\d+.,"message":"some message"}\z/,
158
+ times:1
159
+ end
160
+
161
+ def test_emit_json_merge
162
+ config = %{
163
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
164
+ log_format json_merge
165
+ source_category test
166
+ source_host test
167
+ source_name test
168
+
169
+ }
170
+ driver = create_driver(config)
171
+ time = event_time
172
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
173
+ driver.run do
174
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => '{"foo2":"bar2"}'})
175
+ end
176
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
177
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
178
+ body: /\A{"timestamp":\d+,"foo":"bar","foo2":"bar2"}\z/,
179
+ times:1
180
+ end
181
+
182
+ def test_emit_json_merge_timestamp
183
+ config = %{
184
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
185
+ log_format json_merge
186
+ source_category test
187
+ source_host test
188
+ source_name test
189
+
190
+ }
191
+ driver = create_driver(config)
192
+ time = event_time
193
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
194
+ driver.run do
195
+ driver.feed("output.test", time, {'message' => '{"timestamp":123}'})
196
+ end
197
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
198
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
199
+ body: /\A{"timestamp":123}\z/,
200
+ times:1
201
+ end
202
+
203
+ def test_emit_with_sumo_metadata
204
+ config = %{
205
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
206
+ log_format json
207
+ }
208
+ driver = create_driver(config)
209
+ time = event_time
210
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
211
+ ENV['HOST'] = "foo"
212
+ driver.run do
213
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => 'test', '_sumo_metadata' => {
214
+ "host": "#{ENV['HOST']}",
215
+ "source": "${tag}",
216
+ "category": "${tag[1]}"
217
+ }})
218
+ end
219
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
220
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'foo', 'X-Sumo-Name'=>'output.test'},
221
+ body: /\A{"timestamp":\d+.,"foo":"bar","message":"test"}\z/,
222
+ times:1
223
+ end
224
+
225
+ def test_emit_json_no_timestamp
226
+ config = %{
227
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
228
+ log_format json
229
+ source_category test
230
+ source_host test
231
+ source_name test
232
+ add_timestamp false
233
+ }
234
+ driver = create_driver(config)
235
+ time = event_time
236
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
237
+ driver.run do
238
+ driver.feed("output.test", time, {'foo' => 'bar', 'message' => 'test'})
239
+ end
240
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
241
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
242
+ body: /\A{"foo":"bar","message":"test"}\z/,
243
+ times:1
244
+ end
245
+
246
+ def test_emit_json_timestamp_key
247
+ config = %{
248
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
249
+ log_format json
250
+ source_category test
251
+ source_host test
252
+ source_name test
253
+ timestamp_key ts
254
+ }
255
+ driver = create_driver(config)
256
+ time = event_time
257
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
258
+ driver.run do
259
+ driver.feed("output.test", time, {'message' => 'test'})
260
+ end
261
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
262
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test'},
263
+ body: /\A{"ts":\d+.,"message":"test"}\z/,
264
+ times:1
265
+ end
266
+
267
+ def test_emit_graphite
268
+ config = %{
269
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
270
+ data_type metrics
271
+ metric_data_format graphite
272
+ source_category test
273
+ source_host test
274
+ source_name test
275
+ }
276
+ driver = create_driver(config)
277
+ time = event_time
278
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
279
+ driver.run do
280
+ driver.feed("output.test", time, {'message' =>'prod.lb-1.cpu 87.2 1501753030'})
281
+ end
282
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
283
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'Content-Type'=>'application/vnd.sumologic.graphite'},
284
+ body: /\Aprod.lb-1.cpu 87.2 1501753030\z/,
285
+ times:1
286
+ end
287
+
288
+ def test_emit_carbon
289
+ config = %{
290
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
291
+ data_type metrics
292
+ metric_data_format carbon2
293
+ source_category test
294
+ source_host test
295
+ source_name test
296
+ }
297
+ driver = create_driver(config)
298
+ time = event_time
299
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
300
+ driver.run do
301
+ driver.feed("output.test", time, {'message' =>'cluster=prod node=lb-1 metric=cpu ip=2.2.3.4 team=infra 87.2 1501753030'})
302
+ end
303
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
304
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'Content-Type'=>'application/vnd.sumologic.carbon2'},
305
+ body: /\Acluster=prod node=lb-1 metric=cpu ip=2.2.3.4 team=infra 87.2 1501753030\z/,
306
+ times:1
307
+ end
308
+
309
+ def test_emit_prometheus
310
+ config = %{
311
+ endpoint https://collectors.sumologic.com/v1/receivers/http/1234
312
+ data_type metrics
313
+ metric_data_format prometheus
314
+ source_category test
315
+ source_host test
316
+ source_name test
317
+ }
318
+ driver = create_driver(config)
319
+ time = event_time
320
+ stub_request(:post, 'https://collectors.sumologic.com/v1/receivers/http/1234')
321
+ driver.run do
322
+ driver.feed("output.test", time, {'message' =>'cpu{cluster="prod", node="lb-1"} 87.2 1501753030'})
323
+ end
324
+ assert_requested :post, "https://collectors.sumologic.com/v1/receivers/http/1234",
325
+ headers: {'X-Sumo-Category'=>'test', 'X-Sumo-Client'=>'fluentd-output', 'X-Sumo-Host'=>'test', 'X-Sumo-Name'=>'test', 'Content-Type'=>'application/vnd.sumologic.prometheus'},
326
+ body: 'cpu{cluster="prod", node="lb-1"} 87.2 1501753030',
327
+ times:1
328
+ end
329
+
330
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-sumologic_output
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Steven Adams
8
+ - Frank Reno
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-03-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: test-unit
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 3.1.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 3.1.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: codecov
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.1.10
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 0.1.10
70
+ - !ruby/object:Gem::Dependency
71
+ name: fluentd
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 0.14.12
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.14.12
84
+ - !ruby/object:Gem::Dependency
85
+ name: httpclient
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 2.8.0
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 2.8.0
98
+ description: Output plugin to SumoLogic HTTP Endpoint
99
+ email:
100
+ - stevezau@gmail.com
101
+ - frank.reno@me.com
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".travis.yml"
108
+ - CHANGELOG.md
109
+ - Gemfile
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - ci/build.sh
114
+ - fluent-plugin-sumologic_output.gemspec
115
+ - lib/fluent/plugin/out_sumologic.rb
116
+ - test/helper.rb
117
+ - test/plugin/test_out_sumologic.rb
118
+ homepage: https://github.com/SumoLogic/fluentd-output-sumologic
119
+ licenses:
120
+ - Apache-2.0
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 2.0.0
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubygems_version: 3.0.3
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Output plugin to SumoLogic HTTP Endpoint
141
+ test_files:
142
+ - test/helper.rb
143
+ - test/plugin/test_out_sumologic.rb