gitlab-fluent-plugin-redis-slowlog 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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