fluent-plugin-grafana-loki 1.2.7 → 1.2.14

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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +54 -198
  3. data/bin/setup +1 -1
  4. data/lib/fluent/plugin/out_loki.rb +56 -26
  5. metadata +52 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6272020eefeef15ea9b65b49ede71e60c08c298c7c56d2ca366a95130fbf3f3a
4
- data.tar.gz: b3699f4d8dcc778bfc63d6d2a0fe456ecfd95fb55dfbf6048af0846fdd741259
3
+ metadata.gz: 1fd9308b0afb758b4718b7ad46fc5a3c154400a93514ea79fe3453279abe5cdc
4
+ data.tar.gz: b67621f7aa29c775f6e81f546623dec74d326097071f2ce5bd04523ffd865769
5
5
  SHA512:
6
- metadata.gz: 15cd081338b9da5c2b8ea7212d4ebd0cb455782cb02722992bdd671e6715d960c6a1bfb828d14a763c60175cc82d156f912a624dde81072eaeb85c726b8a06c5
7
- data.tar.gz: dbec238d8c2e2b52c5508cc1cebe9a55677dfbb6de26de33af2b45399742fd57b8a5a727b6e763560b4f775eafa5172c4fed86e4cd9162ad06b90e2233708851
6
+ metadata.gz: 5e6fee1480cdd594f027cbbb22e503a7ecc0dd2384a6b5d46083eed2a6cdbb820d3c3bfe8f98f2cd197d89cbee2876d8a6659d57a070980b609e6b0cc99fec7a
7
+ data.tar.gz: 5452556eed1158c3ccaf5bcb5509a773ff89ad4f64e7b3e778603aef0d221cbd2d1ea5ff0e7bed47b1d68b51abae9bf58fccab5996b9ca67bcbfaf81a977cafe
data/README.md CHANGED
@@ -1,228 +1,84 @@
1
- # fluent-plugin-grafana-loki
1
+ # Fluentd output plugin
2
2
 
3
- [Fluentd](https://fluentd.org/) output plugin to ship logs to a Loki server.
3
+ [Fluentd](https://fluentd.org/) is a data collector for unified logging layer, it can be configured with the Loki output plugin, provided in this folder, to ship logs to Loki.
4
4
 
5
- This plugin offers two line formats and uses protobuf to send compressed data to Loki.
5
+ See [docs/client/fluentd/README.md](../../docs/sources/clients/fluentd/_index.md) for detailed information.
6
6
 
7
- Key features:
8
- * extra_labels - labels to be added to every line of a logfile, useful for designating environments
9
- * label - This section allows you to specify labels from your log fields
10
-
11
- ## Installation
12
-
13
- ```
14
- $ gem install fluent-plugin-grafana-loki
15
- ```
16
-
17
- ## Usage
18
- In your Fluentd configuration, use `@type loki`. Additional configuration is optional, default values would look like this:
19
- ```
20
- <match **>
21
- @type loki
22
- url "https://logs-us-west1.grafana.net"
23
- username "#{ENV['LOKI_USERNAME']}"
24
- password "#{ENV['LOKI_PASSWORD']}"
25
- extra_labels {"env":"dev"}
26
- flush_interval 10s
27
- flush_at_shutdown true
28
- buffer_chunk_limit 1m
29
- </match>
30
- ```
7
+ ## Development
31
8
 
32
- ### Using labels
9
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
33
10
 
34
- Simple label from top level attribute
35
- ```
36
- <match mytag>
37
- @type loki
38
- # ...
39
- <label>
40
- fluentd_worker
41
- </label>
42
- # ...
43
- </match>
44
- ```
11
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `fluent-plugin-grafana-loki.gemspec`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
12
 
46
- You can rewrite the label keys as well as the following
13
+ To create the gem: `gem build fluent-plugin-grafana-loki.gemspec`
47
14
 
48
- ```
49
- <match mytag>
50
- @type loki
51
- # ...
52
- <label>
53
- worker fluentd_worker
54
- </label>
55
- # ...
56
- </match>
57
- ```
15
+ Useful additions:
16
+ `gem install rubocop`
58
17
 
59
- You can use record accessor syntax for nested field. https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax
18
+ ## Testing
60
19
 
61
- ```
62
- <match mytag>
63
- @type loki
64
- # ...
65
- <label>
66
- container $.kubernetes.container
67
- </label>
68
- # ...
69
- </match>
70
- ```
20
+ Start Loki using:
71
21
 
72
- ### Extracting Kubernetes labels
73
-
74
- As Kubernetes labels are a list of nested key-value pairs there is a separate option to extract them.
75
- Note that special characters like "`. - /`" will be overwritten with `_`.
76
- Use with the `remove_keys kubernetes` option to eliminate metadata from the log.
77
- ```
78
- <match mytag>
79
- @type loki
80
- # ...
81
- extract_kubernetes_labels true
82
- remove_keys kubernetes
83
- <label>
84
- container $.kubernetes.container
85
- </label>
86
- # ...
87
- </match>
22
+ ```bash
23
+ docker run -it -p 3100:3100 grafana/loki:latest
88
24
  ```
89
25
 
90
- ### Multi-worker usage
26
+ Verify that Loki accept and stores logs:
91
27
 
92
- Loki doesn't currently support out-of-order inserts - if you try to insert a log entry an earlier timestamp after a log entry with with identical labels but a later timestamp, the insert will fail with `HTTP status code: 500, message: rpc error: code = Unknown desc = Entry out of order`. Therefore, in order to use this plugin in a multi worker Fluentd setup, you'll need to include the worker ID in the labels.
93
-
94
- For example, using [fluent-plugin-record-modifier](https://github.com/repeatedly/fluent-plugin-record-modifier):
95
- ```
96
- <filter mytag>
97
- @type record_modifier
98
- <record>
99
- fluentd_worker "#{worker_id}"
100
- </record>
101
- </filter>
102
-
103
- <match mytag>
104
- @type loki
105
- # ...
106
- <label>
107
- fluentd_worker
108
- </label>
109
- # ...
110
- </match>
28
+ ```bash
29
+ curl -H "Content-Type: application/json" -XPOST -s "http://localhost:3100/loki/api/v1/push" --data-raw "{\"streams\": [{\"stream\": {\"job\": \"test\"}, \"values\": [[\"$(date +%s)000000000\", \"fizzbuzz\"]]}]}"
30
+ curl "http://localhost:3100/loki/api/v1/query_range" --data-urlencode 'query={job="test"}' --data-urlencode 'step=300' | jq .data.result
111
31
  ```
112
32
 
113
- ### Using multiple buffer flush threads
114
-
115
- Similarly, when using `flush_thread_count` > 1 in the [`buffer`](https://docs.fluentd.org/configuration/buffer-section#flushing-parameters)
116
- section, a thread identifier must be added as a label to ensure that log chunks flushed in parallel to loki by fluentd always have increasing
117
- times for their unique label sets.
118
-
119
- This plugin automatically adds a `fluentd_thread` label with the name of the buffer flush thread when `flush_thread_count` > 1.
120
-
121
- ## Docker Image
122
-
123
- There is a Docker image `grafana/fluent-plugin-grafana-loki:master` which contains default configuration files to git log information
124
- a host's `/var/log` dir, and from the host's Journald. To use it, you can set the `LOKI_URL`, `LOKI_USERNAME`, and `LOKI_PASSWORD` environment variables (you can leave the USERNAME and PASSWORD blank if they're not used.)
33
+ The expected output is:
125
34
 
126
-
127
- A Docker Swarm Compose configuration that will work looks like:
128
-
129
- ```
130
- services:
131
- fluentd:
132
- image: grafana/fluent-plugin-grafana-loki:master
133
- command:
134
- - "fluentd"
135
- - "-v"
136
- - "-p"
137
- - "/fluentd/plugins"
138
- environment:
139
- LOKI_URL: http://loki:3100
140
- LOKI_USERNAME:
141
- LOKI_PASSWORD:
142
- deploy:
143
- mode: global
144
- configs:
145
- - source: loki_config
146
- target: /fluentd/etc/loki/loki.conf
147
- networks:
148
- - loki
149
- volumes:
150
- - host_logs:/var/log
151
- # Needed for journald log ingestion:
152
- - /etc/machine-id:/etc/machine-id
153
- - /dev/log:/dev/log
154
- - /var/run/systemd/journal/:/var/run/systemd/journal/
155
- logging:
156
- options:
157
- tag: infra.monitoring
35
+ ```json
36
+ [
37
+ {
38
+ "stream": {
39
+ "job": "test"
40
+ },
41
+ "values": [
42
+ [
43
+ "1588337198000000000",
44
+ "fizzbuzz"
45
+ ]
46
+ ]
47
+ }
48
+ ]
158
49
  ```
159
50
 
160
- ## Configuration
161
-
162
- ### url
163
- The url of the Loki server to send logs to. When sending data the publish path (`/api/prom/push`) will automatically be appended.
164
- By default the url is set to `https://logs-us-west1.grafana.net`, the url of the Grafana Labs preview (hosted Loki)[https://grafana.com/loki] service.
165
-
166
- #### Proxy Support
167
-
168
- Starting with version 0.8.0, this gem uses excon, which supports proxy with environment variables - https://github.com/excon/excon#proxy-support
169
-
170
- ### username / password
171
- Specify a username and password if the Loki server requires authentication.
172
- If using the GrafanaLab's hosted Loki, the username needs to be set to your instanceId and the password should be a Grafana.com api key.
173
-
174
- ### tenant
175
- Loki is a multi-tenant log storage platform and all requests sent must include a tenant. For some installations the tenant will be set automatically by an authenticating proxy. Otherwise you can define a tenant to be passed through. The tenant can be any string value.
176
-
177
- ### client certificate verification
178
- Specify a pair of client certificate and private key with `cert` and `key` if a reverse proxy with client certificate verification is configured in front of Loki. `ca_cert` can also be specified if the server uses custom certificate authority.
51
+ Start and send test logs with Fluentd using:
179
52
 
53
+ ```bash
54
+ LOKI_URL=http://{{ IP }}:3100 make fluentd-test
180
55
  ```
181
- <match **>
182
- @type loki
183
56
 
184
- url "https://loki"
57
+ Verify that syslogs are being feeded into Loki:
185
58
 
186
- cert /path/to/certificate.pem
187
- key /path/to/key.key
188
- ca_cert /path/to/ca.pem
189
-
190
- ...
191
- </match>
59
+ ```bash
60
+ curl "http://localhost:3100/loki/api/v1/query_range" --data-urlencode 'query={job="fluentd"}' --data-urlencode 'step=300' | jq .data.result
192
61
  ```
193
62
 
194
- ### output format
195
- Loki is intended to index and group log streams using only a small set of labels. It is not intended for full-text indexing. When sending logs to Loki the majority of log message will be sent as a single log "line".
196
-
197
- There are few configurations settings to control the output format.
198
- - extra_labels: (default: nil) set of labels to include with every Loki stream. eg `{"env":"dev", "datacenter": "dc1"}`
199
- - remove_keys: (default: nil) comma separated list of needless record keys to remove. All other keys will be placed into the log line. You can use [record_accessor syntax](https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax).
200
- - line_format: format to use when flattening the record to a log line. Valid values are "json" or "key_value". If set to "json" the log line sent to Loki will be the fluentd record (excluding any keys extracted out as labels) dumped as json. If set to "key_value", the log line will be each item in the record concatenated together (separated by a single space) in the format `<key>=<value>`.
201
- - drop_single_key: if set to true and after extracting label_keys a record only has a single key remaining, the log line sent to Loki will just be the value of the record key.
202
-
203
- ### Buffer options
63
+ The expected output is:
204
64
 
205
- `fluentd-plugin-loki` extends [Fluentd's builtin Output plugin](https://docs.fluentd.org/v1.0/articles/output-plugin-overview) and use `compat_parameters` plugin helper. It adds the following options:
206
-
207
- ```
208
- buffer_type memory
209
- flush_interval 10s
210
- retry_limit 17
211
- retry_wait 1.0
212
- num_threads 1
65
+ ```json
66
+ [
67
+ {
68
+ "stream": {
69
+ "job": "fluentd"
70
+ },
71
+ "values": [
72
+ [
73
+ "1588336950379591919",
74
+ "log=\"May 1 14:42:30 ibuprofen avahi-daemon[859]: New relevant interface vethb503225.IPv6 for mDNS.\""
75
+ ],
76
+ ...
77
+ ]
78
+ }
79
+ ]
213
80
  ```
214
81
 
215
- ## Development
216
-
217
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
218
-
219
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `fluent-plugin-grafana-loki.gemspec`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
220
-
221
- To create the gem: `gem build fluent-plugin-grafana-loki.gemspec`
222
-
223
- Useful additions:
224
- `gem install rubocop`
225
-
226
82
  ## Copyright
227
83
 
228
84
  * Copyright(c) 2018- Grafana Labs
data/bin/setup CHANGED
@@ -3,5 +3,5 @@ set -euo pipefail
3
3
  IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
- sudo gem install bundle
6
+ gem install bundler
7
7
  bundle install
@@ -15,9 +15,9 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
+ require 'fluent/env'
18
19
  require 'fluent/plugin/output'
19
20
  require 'net/http'
20
- require 'uri'
21
21
  require 'yajl'
22
22
  require 'time'
23
23
 
@@ -27,6 +27,8 @@ module Fluent
27
27
  class LokiOutput < Fluent::Plugin::Output # rubocop:disable Metrics/ClassLength
28
28
  Fluent::Plugin.register_output('loki', self)
29
29
 
30
+ class LogPostError < StandardError; end
31
+
30
32
  helpers :compat_parameters, :record_accessor
31
33
 
32
34
  attr_accessor :record_accessors
@@ -34,7 +36,7 @@ module Fluent
34
36
  DEFAULT_BUFFER_TYPE = 'memory'
35
37
 
36
38
  desc 'url of loki server'
37
- config_param :url, :string, default: 'https://logs-us-west1.grafana.net'
39
+ config_param :url, :string, default: 'https://logs-prod-us-central1.grafana.net'
38
40
 
39
41
  desc 'BasicAuth credentials'
40
42
  config_param :username, :string, default: nil
@@ -47,6 +49,9 @@ module Fluent
47
49
  desc 'TLS'
48
50
  config_param :ca_cert, :string, default: nil
49
51
 
52
+ desc 'Disable server certificate verification'
53
+ config_param :insecure_tls, :bool, default: false
54
+
50
55
  desc 'Loki tenant id'
51
56
  config_param :tenant, :string, default: nil
52
57
 
@@ -70,9 +75,14 @@ module Fluent
70
75
  config_set_default :chunk_keys, []
71
76
  end
72
77
 
73
- def configure(conf)
78
+ def configure(conf) # rubocop:disable Metrics/CyclomaticComplexity
74
79
  compat_parameters_convert(conf, :buffer)
75
80
  super
81
+ @uri = URI.parse(@url + '/loki/api/v1/push')
82
+ unless @uri.is_a?(URI::HTTP) || @uri.is_a?(URI::HTTPS)
83
+ raise Fluent::ConfigError, 'url parameter must be valid HTTP'
84
+ end
85
+
76
86
  @record_accessors = {}
77
87
  conf.elements.select { |element| element.name == 'label' }.each do |element|
78
88
  element.each_pair do |k, v|
@@ -126,31 +136,19 @@ module Fluent
126
136
  payload = generic_to_loki(chunk)
127
137
  body = { 'streams' => payload }
128
138
 
129
- # add ingest path to loki url
130
- uri = URI.parse(url + '/loki/api/v1/push')
139
+ tenant = extract_placeholders(@tenant, chunk) if @tenant
131
140
 
132
- req = Net::HTTP::Post.new(
133
- uri.request_uri
134
- )
135
- req.add_field('Content-Type', 'application/json')
136
- req.add_field('X-Scope-OrgID', @tenant) if @tenant
137
- req.body = Yajl.dump(body)
138
- req.basic_auth(@username, @password) if @username
141
+ # add ingest path to loki url
142
+ res = loki_http_request(body, tenant)
139
143
 
140
- opts = ssl_opts(uri)
144
+ return if res.is_a?(Net::HTTPSuccess)
141
145
 
142
- log.debug "sending #{req.body.length} bytes to loki"
143
- res = Net::HTTP.start(uri.hostname, uri.port, **opts) { |http| http.request(req) }
144
- unless res&.is_a?(Net::HTTPSuccess)
145
- res_summary = if res
146
- "#{res.code} #{res.message} #{res.body}"
147
- else
148
- 'res=nil'
149
- end
150
- log.warn "failed to #{req.method} #{uri} (#{res_summary})"
151
- log.warn Yajl.dump(body)
146
+ res_summary = "#{res.code} #{res.message} #{res.body}"
147
+ log.warn "failed to write post to #{@uri} (#{res_summary})"
148
+ log.debug Yajl.dump(body)
152
149
 
153
- end
150
+ # Only retry 429 and 500s
151
+ raise(LogPostError, res_summary) if res.is_a?(Net::HTTPTooManyRequests) || res.is_a?(Net::HTTPServerError)
154
152
  end
155
153
 
156
154
  def ssl_opts(uri)
@@ -158,14 +156,22 @@ module Fluent
158
156
  use_ssl: uri.scheme == 'https'
159
157
  }
160
158
 
159
+ # Disable server TLS certificate verification
160
+ if @insecure_tls
161
+ opts = opts.merge(
162
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
163
+ )
164
+ end
165
+
166
+ # Verify client TLS certificate
161
167
  if !@cert.nil? && !@key.nil?
162
168
  opts = opts.merge(
163
- verify_mode: OpenSSL::SSL::VERIFY_PEER,
164
169
  cert: @cert,
165
170
  key: @key
166
171
  )
167
172
  end
168
173
 
174
+ # Specify custom certificate authority
169
175
  unless @ca_cert.nil?
170
176
  opts = opts.merge(
171
177
  ca_file: @ca_cert
@@ -183,6 +189,24 @@ module Fluent
183
189
 
184
190
  private
185
191
 
192
+ def loki_http_request(body, tenant)
193
+ req = Net::HTTP::Post.new(
194
+ @uri.request_uri
195
+ )
196
+ req.add_field('Content-Type', 'application/json')
197
+ req.add_field('X-Scope-OrgID', tenant) if tenant
198
+ req.body = Yajl.dump(body)
199
+ req.basic_auth(@username, @password) if @username
200
+
201
+ opts = ssl_opts(@uri)
202
+
203
+ msg = "sending #{req.body.length} bytes to loki"
204
+ msg += " (tenant: \"#{tenant}\")" if tenant
205
+ log.debug msg
206
+
207
+ Net::HTTP.start(@uri.host, @uri.port, **opts) { |http| http.request(req) }
208
+ end
209
+
186
210
  def numeric?(val)
187
211
  !Float(val).nil?
188
212
  rescue StandardError
@@ -215,7 +239,13 @@ module Fluent
215
239
  end
216
240
 
217
241
  def to_nano(time)
218
- time.to_i * (10**9) + time.nsec
242
+ # time is a Fluent::EventTime object, or an Integer which represents unix timestamp (seconds from Epoch)
243
+ # https://docs.fluentd.org/plugin-development/api-plugin-output#chunk-each-and-block
244
+ if time.is_a?(Fluent::EventTime)
245
+ time.to_i * (10**9) + time.nsec
246
+ else
247
+ time.to_i * (10**9)
248
+ end
219
249
  end
220
250
 
221
251
  def record_to_line(record)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-grafana-loki
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.7
4
+ version: 1.2.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - woodsaj
@@ -10,8 +10,28 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-01-17 00:00:00.000000000 Z
13
+ date: 2020-07-23 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fluentd
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 1.9.3
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: '2'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.9.3
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '2'
15
35
  - !ruby/object:Gem::Dependency
16
36
  name: bundler
17
37
  requirement: !ruby/object:Gem::Requirement
@@ -55,25 +75,47 @@ dependencies:
55
75
  - !ruby/object:Gem::Version
56
76
  version: '3.0'
57
77
  - !ruby/object:Gem::Dependency
58
- name: fluentd
78
+ name: rubocop-rspec
59
79
  requirement: !ruby/object:Gem::Requirement
60
80
  requirements:
61
81
  - - ">="
62
82
  - !ruby/object:Gem::Version
63
- version: 0.14.10
64
- - - "<"
83
+ version: '0'
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
65
89
  - !ruby/object:Gem::Version
66
- version: '2'
67
- type: :runtime
90
+ version: '0'
91
+ - !ruby/object:Gem::Dependency
92
+ name: simplecov
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ type: :development
68
99
  prerelease: false
69
100
  version_requirements: !ruby/object:Gem::Requirement
70
101
  requirements:
71
102
  - - ">="
72
103
  - !ruby/object:Gem::Version
73
- version: 0.14.10
74
- - - "<"
104
+ version: '0'
105
+ - !ruby/object:Gem::Dependency
106
+ name: test-unit
107
+ requirement: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
75
110
  - !ruby/object:Gem::Version
76
- version: '2'
111
+ version: '0'
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
77
119
  description: Output plugin to ship logs to a Grafana Loki server
78
120
  email:
79
121
  - awoods@grafana.com