fluent-plugin-logtail 0.1.0
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 +7 -0
- data/.github/workflows/main.yml +29 -0
- data/.gitignore +16 -0
- data/Gemfile +2 -0
- data/LICENSE.md +15 -0
- data/README.md +31 -0
- data/fluent-plugin-logtail.gemspec +28 -0
- data/lib/fluent/plugin/out_logtail.rb +80 -0
- data/spec/fluent/plugin/out_logtail_spec.rb +63 -0
- data/spec/spec_helper.rb +20 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0c8596cf46b0faa3a9d7e580d453d0cec5af12bd1b75d42232f72c57a834a7b
|
4
|
+
data.tar.gz: 60b7f73e13bedafe63b2cbfb80338ba15644387c292312471cff7247e333df5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4103a98491a69624c5354facafd04735c3ba85a2ceb2d8c179435e46f9c82e0ce3376287717e830635c75842ee22aed02822d2cf1afe1f1a931dc820ae2cc063
|
7
|
+
data.tar.gz: 83bb7f6e2b67ad1700f1b59b1f52efaa4d33d386e671e98af0dd7b8686df93bb44188f66a7ec42dfad10412df7bbe47323894cf11e39314e8e1fc026f0e98629
|
@@ -0,0 +1,29 @@
|
|
1
|
+
name: build
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
|
8
|
+
runs-on: ubuntu-20.04
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
ruby-version:
|
13
|
+
- 3.0.0
|
14
|
+
- 2.7.2
|
15
|
+
- 2.6.6
|
16
|
+
- 2.5.8
|
17
|
+
- 2.4.10
|
18
|
+
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v2
|
21
|
+
|
22
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
23
|
+
uses: ruby/setup-ruby@v1
|
24
|
+
with:
|
25
|
+
ruby-version: ${{ matrix.ruby-version }}
|
26
|
+
bundler-cache: true
|
27
|
+
|
28
|
+
- name: Run tests
|
29
|
+
run: bundle exec rspec
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# License
|
2
|
+
|
3
|
+
Copyright (c) 2021, Logtail
|
4
|
+
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
6
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
7
|
+
and this permission notice appear in all copies.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
11
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
13
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
14
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
15
|
+
THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# 🪵 Fluent::Plugin::Logtail, a plugin for [Fluentd](http://fluentd.org)
|
2
|
+
|
3
|
+
[](https://github.com/logtail/fluentd-plugin-logtail/actions/workflows/main.yml)
|
4
|
+
|
5
|
+
A Fluentd plugin that delivers events to the [Logtail.com logging service](https://logtail.com). It uses batching, msgpack, and retry logic for highly efficient and reliable delivery of log data.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install fluent-plugin-logtail
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
In your Fluentd configuration, use `@type logtail`:
|
16
|
+
|
17
|
+
```
|
18
|
+
<match your_match>
|
19
|
+
@type logtail
|
20
|
+
source_token YOUR_SOURCE_TOKEN
|
21
|
+
# ip 127.0.0.1
|
22
|
+
buffer_chunk_limit 1m # Must be < 5m
|
23
|
+
flush_at_shutdown true # Only needed with file buffer
|
24
|
+
</match>
|
25
|
+
```
|
26
|
+
|
27
|
+
## Configuration
|
28
|
+
|
29
|
+
* `source_token` - This is your [Logtail source token](https://logtail.com).
|
30
|
+
|
31
|
+
For advanced configuration options, please see to the [buffered output parameters documentation.](http://docs.fluentd.org/articles/output-plugin-overview#buffered-output-parameters).
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'fluent-plugin-logtail'
|
6
|
+
s.version = '0.1.0'
|
7
|
+
s.date = Date.today.to_s
|
8
|
+
s.summary = 'Logtail.com plugin for Fluentd'
|
9
|
+
s.description = 'Streams Fluentd logs to the Logtail.com logging service.'
|
10
|
+
s.authors = ['Logtail.com']
|
11
|
+
s.email = 'hello@logtail.com'
|
12
|
+
s.homepage = 'https://github.com/logtail/fluent-plugin-logtail'
|
13
|
+
s.license = 'ISC'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.4.0".freeze)
|
21
|
+
|
22
|
+
s.add_runtime_dependency('fluentd', '> 1', '< 2')
|
23
|
+
s.add_runtime_dependency('http', '~> 2.0', '>= 2.0.3')
|
24
|
+
|
25
|
+
s.add_development_dependency('rspec', '~> 3.4')
|
26
|
+
s.add_development_dependency('test-unit', '~> 3.3.9')
|
27
|
+
s.add_development_dependency('webmock', '~> 2.3')
|
28
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'fluent/output'
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
class LogtailOutput < Fluent::BufferedOutput
|
5
|
+
Fluent::Plugin.register_output('logtail', self)
|
6
|
+
|
7
|
+
VERSION = "0.1.0".freeze
|
8
|
+
CONTENT_TYPE = "application/msgpack".freeze
|
9
|
+
HOST = "https://in.logtail.com".freeze
|
10
|
+
PATH = "/".freeze
|
11
|
+
MAX_ATTEMPTS = 3.freeze
|
12
|
+
RETRYABLE_CODES = [429, 500, 502, 503, 504].freeze
|
13
|
+
USER_AGENT = "Logtail Logstash/#{VERSION}".freeze
|
14
|
+
|
15
|
+
config_param :source_token, :string, secret: true
|
16
|
+
config_param :ip, :string, default: nil
|
17
|
+
|
18
|
+
def configure(conf)
|
19
|
+
source_token = conf["source_token"]
|
20
|
+
@headers = {
|
21
|
+
"Authorization" => "Bearer #{source_token}",
|
22
|
+
"Content-Type" => CONTENT_TYPE,
|
23
|
+
"User-Agent" => USER_AGENT
|
24
|
+
}
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def start
|
29
|
+
super
|
30
|
+
require 'http'
|
31
|
+
HTTP.default_options = {:keep_alive_timeout => 29}
|
32
|
+
@http_client = HTTP.persistent(HOST)
|
33
|
+
end
|
34
|
+
|
35
|
+
def shutdown
|
36
|
+
@http_client.close if @http_client
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def format(tag, time, record)
|
41
|
+
record.merge("dt" => Time.at(time).utc.iso8601).to_msgpack
|
42
|
+
end
|
43
|
+
|
44
|
+
def write(chunk)
|
45
|
+
deliver(chunk, 1)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def deliver(chunk, attempt)
|
50
|
+
if attempt > MAX_ATTEMPTS
|
51
|
+
log.error("msg=\"Max attempts exceeded dropping chunk\" attempt=#{attempt}")
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
|
55
|
+
body = chunk.read
|
56
|
+
response = @http_client.headers(@headers).post(PATH, body: body)
|
57
|
+
response.flush
|
58
|
+
code = response.code
|
59
|
+
|
60
|
+
if code >= 200 && code <= 299
|
61
|
+
true
|
62
|
+
elsif RETRYABLE_CODES.include?(code)
|
63
|
+
sleep_time = sleep_for_attempt(attempt)
|
64
|
+
log.warn("msg=\"Retryable response from the Logtail API\" " +
|
65
|
+
"code=#{code} attempt=#{attempt} sleep=#{sleep_time}")
|
66
|
+
sleep(sleep_time)
|
67
|
+
deliver(chunk, attempt + 1)
|
68
|
+
else
|
69
|
+
log.error("msg=\"Fatal response from the Logtail API\" code=#{code} attempt=#{attempt}")
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def sleep_for_attempt(attempt)
|
75
|
+
sleep_for = attempt ** 2
|
76
|
+
sleep_for = sleep_for <= 60 ? sleep_for : 60
|
77
|
+
(sleep_for / 2) + (rand(0..sleep_for) / 2)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "fluent/plugin/out_logtail"
|
3
|
+
|
4
|
+
describe Fluent::LogtailOutput do
|
5
|
+
let(:config) do
|
6
|
+
%{
|
7
|
+
source_token abcd1234
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:driver) do
|
12
|
+
tag = "test"
|
13
|
+
Fluent::Test::BufferedOutputTestDriver.new(Fluent::LogtailOutput, tag) {
|
14
|
+
# v0.12's test driver assume format definition. This simulates ObjectBufferedOutput format
|
15
|
+
if !defined?(Fluent::Plugin::Output)
|
16
|
+
def format(tag, time, record)
|
17
|
+
[time, record].to_msgpack
|
18
|
+
end
|
19
|
+
end
|
20
|
+
}.configure(config)
|
21
|
+
end
|
22
|
+
let(:record) do
|
23
|
+
{'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
|
24
|
+
end
|
25
|
+
|
26
|
+
before(:each) do
|
27
|
+
Fluent::Test.setup
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#write" do
|
31
|
+
it "should send a chunked request to the Logtail API" do
|
32
|
+
stub = stub_request(:post, "https://in.logtail.com/").
|
33
|
+
with(
|
34
|
+
:body => start_with("\x85\xA3age\x1A\xAArequest_id\xA242\xA9parent_id\xA6parent\xAArouting_id\xA7routing\xA2dt\xB4".force_encoding("ASCII-8BIT")),
|
35
|
+
:headers => {'Authorization'=>'Bearer abcd1234', 'Connection'=>'Keep-Alive', 'Content-Type'=>'application/msgpack', 'User-Agent'=>'Logtail Logstash/0.1.0'}
|
36
|
+
).
|
37
|
+
to_return(:status => 200, :body => "", :headers => {})
|
38
|
+
|
39
|
+
driver.emit(record)
|
40
|
+
driver.run
|
41
|
+
|
42
|
+
expect(stub).to have_been_requested.times(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "handles 500s" do
|
46
|
+
stub = stub_request(:post, "https://in.logtail.com/").to_return(:status => 500, :body => "", :headers => {})
|
47
|
+
|
48
|
+
driver.emit(record)
|
49
|
+
driver.run
|
50
|
+
|
51
|
+
expect(stub).to have_been_requested.times(3)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "handle auth failures" do
|
55
|
+
stub = stub_request(:post, "https://in.logtail.com/").to_return(:status => 403, :body => "", :headers => {})
|
56
|
+
|
57
|
+
driver.emit(record)
|
58
|
+
driver.run
|
59
|
+
|
60
|
+
expect(stub).to have_been_requested.times(1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Base
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
# Testing
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
# Webmock
|
9
|
+
require 'webmock/rspec'
|
10
|
+
WebMock.disable_net_connect!
|
11
|
+
|
12
|
+
# Fluent
|
13
|
+
require "fluent/test"
|
14
|
+
|
15
|
+
# Rspec
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.color = true
|
18
|
+
config.order = :random
|
19
|
+
config.warnings = false
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-logtail
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Logtail.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: http
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.0'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.0.3
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.0'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.0.3
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '3.4'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '3.4'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: test-unit
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 3.3.9
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 3.3.9
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: webmock
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '2.3'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '2.3'
|
95
|
+
description: Streams Fluentd logs to the Logtail.com logging service.
|
96
|
+
email: hello@logtail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- ".github/workflows/main.yml"
|
102
|
+
- ".gitignore"
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.md
|
105
|
+
- README.md
|
106
|
+
- fluent-plugin-logtail.gemspec
|
107
|
+
- lib/fluent/plugin/out_logtail.rb
|
108
|
+
- spec/fluent/plugin/out_logtail_spec.rb
|
109
|
+
- spec/spec_helper.rb
|
110
|
+
homepage: https://github.com/logtail/fluent-plugin-logtail
|
111
|
+
licenses:
|
112
|
+
- ISC
|
113
|
+
metadata: {}
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 2.4.0
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubygems_version: 3.2.3
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Logtail.com plugin for Fluentd
|
133
|
+
test_files:
|
134
|
+
- spec/fluent/plugin/out_logtail_spec.rb
|
135
|
+
- spec/spec_helper.rb
|