gitlab-fluent-plugin-redis-slowlog 0.0.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c29fe816731c72b94242e6ea8debf36746f08f6f6d750b88eb95dcab727a006
4
- data.tar.gz: 26792f5c673c1a6ea403e52b0be1473e94802564f3ec2298897348cd3bc5c863
3
+ metadata.gz: d38f425f2f17bdb5aa44efb1c3901240bb1f41f340cef86c9cca6834716e975b
4
+ data.tar.gz: e6739b5077e8d9c6b6482c7de64c80fea53d960cceb22f100ea55237269320f3
5
5
  SHA512:
6
- metadata.gz: a5021486e250895773ffcfb3740cde86fc39cd909f0de98f85069c6592bcb383fd8382256639fa13a5492f5ee8def005197ba3e7e71dafd1e3452543c31b466e
7
- data.tar.gz: 163fdfbbb4461a6fbe78558aa8930a030077fd459bcdc2bcfdc114cf27cf34e247d25192707f104d24bb70e5a55e7c6cb6573c7c65a2da910bce8f4665d90b1b
6
+ metadata.gz: ae4c9a0fafe66b7df1d9c49f639f882c5c834ad368dab29a9d0599a5af75ae4e73f4f113f4b4e3e6bc2f71b9aa9358403c48188865ffabd3797302e9add5ea53
7
+ data.tar.gz: 3d748722aa7ae4690f9298c455ee91fbbd4106f1fc505fa98b28f5198722086286a8343b907d10fbea0dab6bd9ad55a368b9f8af3bb1794f7f11b244d1614ff8
@@ -6,6 +6,8 @@ module Fluent
6
6
  class RedisSlowlogInput < Fluent::Plugin::Input
7
7
  Fluent::Plugin.register_input("redis_slowlog", self)
8
8
 
9
+ Entry = Struct.new(:id, :timestamp, :exec_time_us, :command)
10
+
9
11
  config_param :tag, :string
10
12
  config_param :url, :string, default: nil
11
13
  config_param :path, :string, default: nil
@@ -15,12 +17,6 @@ module Fluent
15
17
  config_param :logsize, :integer, default: 128
16
18
  config_param :interval, :integer, default: 10
17
19
 
18
- def initialize
19
- super
20
-
21
- @current_log_id = 0
22
- end
23
-
24
20
  def configure(conf)
25
21
  super
26
22
 
@@ -55,39 +51,49 @@ module Fluent
55
51
  private
56
52
 
57
53
  attr_reader :redis, :interval
58
- attr_accessor :watcher, :watching, :current_log_id
54
+ attr_accessor :watcher, :watching
59
55
 
60
56
  def watch
57
+ # Check the current id of the slowlog, and start logging from there
58
+ current_log_id = get_slowlogs(1).first&.id || -1
59
+
61
60
  while watching
62
61
  sleep interval
63
62
 
64
- self.current_log_id = output(current_log_id)
63
+ current_log_id = output(current_log_id)
65
64
  end
66
65
  end
67
66
 
68
- def output(last_id = 0)
69
- slowlogs = redis.slowlog("get", logsize)
67
+ def output(last_id)
68
+ slowlogs = get_slowlogs(logsize)
70
69
  return last_id if slowlogs.empty?
71
70
 
72
- emit_slowlog(slowlogs)
71
+ # If the latest entry is smaller than what we last saw, redis was restarted
72
+ # Restart logging from the beginning.
73
+ last_id = -1 if slowlogs.first.id < last_id
74
+
75
+ emit_slowlog(slowlogs, last_id)
73
76
 
74
77
  # Return the id of the last slowlog entry we've logged
75
78
  # The first entry is the one that occurred last
76
- slowlogs.first.first
79
+ slowlogs.first.id
77
80
  end
78
81
 
79
- def emit_slowlog(slowlogs)
82
+ def emit_slowlog(slowlogs, last_id)
80
83
  slowlogs.reverse_each do |log|
81
84
  # Don't emit logs for entries we've already logged
82
- next if log.first <= current_log_id
85
+ next if log.id <= last_id
83
86
 
84
- log_hash = { "id" => log[0],
85
- "timestamp" => log[1].to_i,
86
- "exec_time" => log[2],
87
- "command" => log[3] }
88
- router.emit(tag, Time.now.to_i, log_hash)
87
+ log_hash = { "id" => log.id,
88
+ "exec_time" => log.exec_time_us,
89
+ "command" => log.command }
90
+ router.emit(tag, Fluent::EventTime.new(log.timestamp.to_i), log_hash)
89
91
  end
90
92
  end
93
+
94
+ def get_slowlogs(size)
95
+ redis.slowlog("get", size).map { |slowlog_entry| Entry.new(*slowlog_entry.first(4)) }
96
+ end
91
97
  end
92
98
  end
93
99
  end
@@ -6,21 +6,24 @@ describe Fluent::Plugin::RedisSlowlogInput do
6
6
  end
7
7
 
8
8
  let(:plugin) { driver.instance }
9
- let(:slowlog) { [] }
10
- let(:fake_redis) { instance_double(Redis, ping: "PONG", quit: "OK", slowlog: slowlog) }
9
+ let(:fake_redis) { instance_double(Redis, ping: "PONG", quit: "OK", slowlog: []) }
11
10
 
12
11
  subject(:driver) do
13
12
  config_string = config.map { |key, value| "#{key} #{value}" }.join("\n")
14
13
  Fluent::Test::Driver::Input.new(described_class).configure(config_string)
15
14
  end
16
15
 
16
+ def run(**options)
17
+ driver.run({ timeout: 1 }.merge(options))
18
+ end
19
+
17
20
  before do
18
21
  Fluent::Test.setup
19
22
  end
20
23
 
21
24
  context "when redis can't be reached" do
22
25
  it "raises an error" do
23
- expect { driver.run }.to raise_error(Redis::CannotConnectError)
26
+ expect { run }.to raise_error(Redis::CannotConnectError)
24
27
  end
25
28
  end
26
29
 
@@ -40,7 +43,7 @@ describe Fluent::Plugin::RedisSlowlogInput do
40
43
 
41
44
  expect(Redis).to receive(:new).with(redis_params).and_return(fake_redis)
42
45
 
43
- driver.run
46
+ run
44
47
  end
45
48
  end
46
49
 
@@ -63,10 +66,11 @@ describe Fluent::Plugin::RedisSlowlogInput do
63
66
  end
64
67
 
65
68
  it "does not raise errors" do
66
- expect { driver.run }.not_to raise_error
69
+ expect { run }.not_to raise_error
67
70
  end
68
71
 
69
72
  it "polls the slowlog with the configured interval and size" do
73
+ expect(fake_redis).to receive(:slowlog).with("get", 1).ordered
70
74
  expect(plugin).to receive(:sleep).with(0).ordered
71
75
  expect(fake_redis).to receive(:slowlog).with("get", 10).ordered
72
76
  expect(plugin).to receive(:sleep).with(0).ordered
@@ -75,51 +79,76 @@ describe Fluent::Plugin::RedisSlowlogInput do
75
79
  # Limit to 2 cycles
76
80
  allow(plugin).to receive(:watching).thrice.and_return(true, true, false)
77
81
 
78
- driver.run
82
+ run
79
83
  end
80
84
 
81
- context "when the slowlog returns entries" do
82
- let(:slowlog) do
85
+ context "when the slowlog returns entries", :aggregate_failures do
86
+ let(:startup_slowlog) { [[25637, 1590522108, 5, %w[SCAN 0]]] }
87
+ let(:logged_slowlog) do
83
88
  [
84
89
  [25640, 1590522258, 1, %w[ping]],
85
90
  [25639, 1590522249, 1, %w[ping]],
86
91
  [25638, 1590522208, 5, %w[SCAN 0]]
87
92
  ]
88
93
  end
94
+ let(:slowlog) { logged_slowlog + startup_slowlog }
89
95
 
90
96
  let(:expected_entries) do
91
- slowlog.map(&method(:log_entry)).sort_by { |event| event["id"] }
97
+ logged_slowlog.map(&method(:log_entry)).sort_by { |event| event["id"] }
92
98
  end
93
99
 
94
100
  let(:emitted_entries) { driver.events.map(&:last) }
95
101
 
96
102
  it "emits an event for each slowlog in reverse order" do
97
- driver.run(expect_emits: 3)
103
+ expect(fake_redis).to receive(:slowlog).and_return(startup_slowlog, slowlog)
104
+
105
+ run(expect_emits: 3)
98
106
 
99
107
  expect(driver.events.size).to eq(3)
100
108
  expect(emitted_entries).to eq(expected_entries)
101
109
  end
102
110
 
103
111
  it "does not log the same event twice" do
104
- expect(fake_redis).to receive(:slowlog).and_return(slowlog.last(1), slowlog)
112
+ expect(fake_redis).to receive(:slowlog).and_return(startup_slowlog, slowlog.last(2), slowlog)
105
113
 
106
- driver.run(expect_emits: 3)
114
+ run(expect_emits: 3)
107
115
 
108
116
  expect(driver.events.size).to eq(3)
109
117
  expect(emitted_entries).to eq(expected_entries)
110
118
  end
111
119
 
112
120
  it "emits results that can be streamed to fluent using MessagePack" do
113
- driver.run(expect_emits: 3)
121
+ expect(fake_redis).to receive(:slowlog).and_return(startup_slowlog, slowlog)
122
+
123
+ run(expect_emits: 3)
114
124
 
115
125
  expect { driver.events.map(&:to_msgpack) }.not_to raise_error
116
126
  end
127
+
128
+ context "when redis restarts" do
129
+ let(:logged_slowlog) { [[25638, 1590522208, 5, %w[SCAN 0]]] }
130
+ let(:reset_slowlog) do
131
+ [
132
+ [2, 1590522258, 1, %w[ping]],
133
+ [1, 1590522249, 1, %w[ping]]
134
+ ]
135
+ end
136
+
137
+ it "emits all items" do
138
+ reset_entries = reset_slowlog.map(&method(:log_entry)).sort_by { |e| e["id"] }
139
+ expect(fake_redis).to receive(:slowlog).and_return(startup_slowlog, slowlog, [], reset_slowlog)
140
+
141
+ run(expect_emits: 3)
142
+
143
+ expect(emitted_entries.size).to eq(3)
144
+ expect(emitted_entries).to eq(expected_entries + reset_entries)
145
+ end
146
+ end
117
147
  end
118
148
  end
119
149
 
120
150
  def log_entry(slowlog_entry)
121
151
  { "id" => slowlog_entry.first,
122
- "timestamp" => slowlog_entry[1].to_i,
123
152
  "exec_time" => slowlog_entry[2],
124
153
  "command" => slowlog_entry.last }
125
154
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-fluent-plugin-redis-slowlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Van Landuyt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler