fluent-plugin-grafana-loki 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -4
  3. data/lib/fluent/plugin/out_loki.rb +51 -33
  4. metadata +7 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adedfda5ed9ce22ed7a9c46d5497b0b2aa608631df08dc68273349567cadc2e6
4
- data.tar.gz: 8c74cf88dc52bccdb51b5efc72e69a543a2e53988be8ce92402303f3054bbc41
3
+ metadata.gz: 3d29e69ac3bede62dac1fa9aba38b5b96bd322150f13748a85ef91e5a044c5d8
4
+ data.tar.gz: dc521c086b7a88e1163e1257b31dab968b26082655b764b89685e0945e72cc25
5
5
  SHA512:
6
- metadata.gz: 17fba6b641ec604837afe7003fb1332f1b28b83a80f67abfc39cf240ea5b296dc2317f1e7315c6cc08f86b367c3797ee42d42ecbabb416afde05973145d5fed0
7
- data.tar.gz: ceeb3e8d842bfb67d9f95f0c8c6000bb0e1895bf91f4306642a8ec2d8ce3c56d499b70adc42888b9a7cfd8b51132deb9dfdfe253cc631bfa87dc7c84cce51bd1
6
+ metadata.gz: b8fdacb9474dba6bcf8a7395a9126945bc3c123b8cdb318fc95f7658943b5465819e226a8ac65a5c0b1dc0a3d66c9fd8b551170d5b9416601d693484c10f87d4
7
+ data.tar.gz: 025c5f3e296af6e3e19daf132ad0411795386073c1573ba2766984812c2801f5cc985a90ddeb7bba4c736b70538d55047070bb98b6d1dfe6e669ab7437204a89
data/README.md CHANGED
@@ -6,7 +6,7 @@ This plugin offers two line formats and uses protobuf to send compressed data to
6
6
 
7
7
  Key features:
8
8
  * extra_labels - labels to be added to every line of a logfile, useful for designating environments
9
- * label_keys - customizable list of keys for stream labels
9
+ * label - This section allows you to specify labels from your log fields
10
10
 
11
11
  ## Installation
12
12
 
@@ -29,6 +29,64 @@ In your Fluentd configuration, use `@type loki`. Additional configuration is opt
29
29
  </match>
30
30
  ```
31
31
 
32
+ ### Using labels
33
+
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
+ ```
45
+
46
+ You can rewrite the label keys as well as the following
47
+
48
+ ```
49
+ <match mytag>
50
+ @type loki
51
+ # ...
52
+ <label>
53
+ worker fluentd_worker
54
+ </label>
55
+ # ...
56
+ </match>
57
+ ```
58
+
59
+ You can use record accessor syntax for nested field. https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax
60
+
61
+ ```
62
+ <match mytag>
63
+ @type loki
64
+ # ...
65
+ <label>
66
+ container $.kubernetes.container
67
+ </label>
68
+ # ...
69
+ </match>
70
+ ```
71
+
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>
88
+ ```
89
+
32
90
  ### Multi-worker usage
33
91
 
34
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.
@@ -45,7 +103,9 @@ For example, using [fluent-plugin-record-modifier](https://github.com/repeatedly
45
103
  <match mytag>
46
104
  @type loki
47
105
  # ...
48
- label_keys "fluentd_worker"
106
+ <label>
107
+ fluentd_worker
108
+ </label>
49
109
  # ...
50
110
  </match>
51
111
  ```
@@ -112,8 +172,7 @@ Loki is intended to index and group log streams using only a small set of labels
112
172
 
113
173
  There are few configurations settings to control the output format.
114
174
  - extra_labels: (default: nil) set of labels to include with every Loki stream. eg `{"env":"dev", "datacenter": "dc1"}`
115
- - remove_keys: (default: nil) comma separated list of needless record keys to remove. All other keys will be placed into the log line
116
- - label_keys: (default: "job,instance") comma separated list of keys to use as stream labels. All other keys will be placed into the log line
175
+ - 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).
117
176
  - 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>`.
118
177
  - 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.
119
178
 
@@ -24,36 +24,38 @@ require 'time'
24
24
  module Fluent
25
25
  module Plugin
26
26
  # Subclass of Fluent Plugin Output
27
- class LokiOutput < Fluent::Plugin::Output
27
+ class LokiOutput < Fluent::Plugin::Output # rubocop:disable Metrics/ClassLength
28
28
  Fluent::Plugin.register_output('loki', self)
29
29
 
30
- helpers :compat_parameters
30
+ helpers :compat_parameters, :record_accessor
31
+
32
+ attr_accessor :record_accessors
31
33
 
32
34
  DEFAULT_BUFFER_TYPE = 'memory'
33
35
 
34
- # url of loki server
36
+ desc 'url of loki server'
35
37
  config_param :url, :string, default: 'https://logs-us-west1.grafana.net'
36
38
 
37
- # BasicAuth credentials
39
+ desc 'BasicAuth credentials'
38
40
  config_param :username, :string, default: nil
39
41
  config_param :password, :string, default: nil, secret: true
40
42
 
41
- # Loki tenant id
43
+ desc 'Loki tenant id'
42
44
  config_param :tenant, :string, default: nil
43
45
 
44
- # extra labels to add to all log streams
46
+ desc 'extra labels to add to all log streams'
45
47
  config_param :extra_labels, :hash, default: {}
46
48
 
47
- # format to use when flattening the record to a log line
49
+ desc 'format to use when flattening the record to a log line'
48
50
  config_param :line_format, :enum, list: %i[json key_value], default: :key_value
49
51
 
50
- # comma separated list of keys to use as stream lables. All other keys will be placed into the log line
51
- config_param :label_keys, :string, default: 'job,instance'
52
+ desc 'extract kubernetes labels as loki labels'
53
+ config_param :extract_kubernetes_labels, :bool, default: false
52
54
 
53
- # comma separated list of needless record keys to remove
54
- config_param :remove_keys, :string, default: nil
55
+ desc 'comma separated list of needless record keys to remove'
56
+ config_param :remove_keys, :array, default: %w[], value_type: :string
55
57
 
56
- # if a record only has 1 key, then just set the log line to the value and discard the key.
58
+ desc 'if a record only has 1 key, then just set the log line to the value and discard the key.'
57
59
  config_param :drop_single_key, :bool, default: false
58
60
 
59
61
  config_section :buffer do
@@ -64,9 +66,18 @@ module Fluent
64
66
  def configure(conf)
65
67
  compat_parameters_convert(conf, :buffer)
66
68
  super
67
-
68
- @label_keys = @label_keys.split(/\s*,\s*/) if @label_keys
69
- @remove_keys = @remove_keys.split(',').map(&:strip) if @remove_keys
69
+ @record_accessors = {}
70
+ conf.elements.select { |element| element.name == 'label' }.each do |element|
71
+ element.each_pair do |k, v|
72
+ element.key?(k) # to suppress unread configuration warning
73
+ v = k if v.empty?
74
+ @record_accessors[k] = record_accessor_create(v)
75
+ end
76
+ end
77
+ @remove_keys_accessors = []
78
+ @remove_keys.each do |key|
79
+ @remove_keys_accessors.push(record_accessor_create(key))
80
+ end
70
81
  end
71
82
 
72
83
  def multi_workers_ready?
@@ -84,7 +95,7 @@ module Fluent
84
95
  def write(chunk)
85
96
  # streams by label
86
97
  payload = generic_to_loki(chunk)
87
- body = { 'streams': payload }
98
+ body = { 'streams' => payload }
88
99
 
89
100
  # add ingest path to loki url
90
101
  uri = URI.parse(url + '/api/prom/push')
@@ -101,7 +112,7 @@ module Fluent
101
112
  }
102
113
  log.debug "sending #{req.body.length} bytes to loki"
103
114
  res = Net::HTTP.start(uri.hostname, uri.port, **opts) { |http| http.request(req) }
104
- unless res && res.is_a?(Net::HTTPSuccess)
115
+ unless res&.is_a?(Net::HTTPSuccess)
105
116
  res_summary = if res
106
117
  "#{res.code} #{res.message} #{res.body}"
107
118
  else
@@ -135,10 +146,8 @@ module Fluent
135
146
  data_labels = {} if data_labels.nil?
136
147
  data_labels = data_labels.merge(@extra_labels)
137
148
 
138
- unless data_labels.nil?
139
- data_labels.each do |k, v|
140
- formatted_labels.push("#{k}=\"#{v}\"")
141
- end
149
+ data_labels.each do |k, v|
150
+ formatted_labels.push(%(#{k}="#{v.gsub('"', '\\"')}")) if v
142
151
  end
143
152
  '{' + formatted_labels.join(',') + '}'
144
153
  end
@@ -147,7 +156,7 @@ module Fluent
147
156
  payload = []
148
157
  streams.each do |k, v|
149
158
  # create a stream for each label set.
150
- # Additionally sort the entries by timestamp just incase we
159
+ # Additionally sort the entries by timestamp just in case we
151
160
  # got them out of order.
152
161
  # 'labels' => '{worker="0"}',
153
162
  payload.push(
@@ -169,7 +178,7 @@ module Fluent
169
178
  when :key_value
170
179
  formatted_labels = []
171
180
  record.each do |k, v|
172
- formatted_labels.push("#{k}=\"#{v}\"")
181
+ formatted_labels.push(%(#{k}="#{v}"))
173
182
  end
174
183
  line = formatted_labels.join(' ')
175
184
  end
@@ -177,22 +186,31 @@ module Fluent
177
186
  line
178
187
  end
179
188
 
189
+ #
180
190
  # convert a line to loki line with labels
181
191
  def line_to_loki(record)
182
192
  chunk_labels = {}
183
193
  line = ''
184
194
  if record.is_a?(Hash)
185
- # remove needless keys.
186
- @remove_keys.each { |v|
187
- record.delete(v)
188
- } if @remove_keys
189
- # extract white listed record keys into labels.
190
- @label_keys.each do |k|
191
- if record.key?(k)
192
- chunk_labels[k] = record[k]
193
- record.delete(k)
195
+ @record_accessors&.each do |name, accessor|
196
+ new_key = name.gsub(%r{[.\-\/]}, '_')
197
+ chunk_labels[new_key] = accessor.call(record)
198
+ accessor.delete(record)
199
+ end
200
+
201
+ if @extract_kubernetes_labels && record.key?('kubernetes')
202
+ kubernetes_labels = record['kubernetes']['labels']
203
+ kubernetes_labels.each_key do |l|
204
+ new_key = l.gsub(%r{[.\-\/]}, '_')
205
+ chunk_labels[new_key] = kubernetes_labels[l]
194
206
  end
195
- end if @label_keys
207
+ end
208
+
209
+ # remove needless keys.
210
+ @remove_keys_accessors&.each do |deleter|
211
+ deleter.delete(record)
212
+ end
213
+
196
214
  line = record_to_line(record)
197
215
  else
198
216
  line = record.to_s
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.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - woodsaj
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-07-26 00:00:00.000000000 Z
12
+ date: 2019-10-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1.15'
20
+ version: '0'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '1.15'
27
+ version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 3.0.4
108
+ rubygems_version: 3.0.3
109
109
  signing_key:
110
110
  specification_version: 4
111
111
  summary: Output plugin to ship logs to a Grafana Loki server