fluent-plugin-grafana-loki 1.0.2 → 1.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.
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