rb.rotate 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.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +32 -0
- data/LICENSE.txt +20 -0
- data/README.md +81 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/bin/rb.rotate +12 -0
- data/lib/rb.rotate.rb +30 -0
- data/lib/rb.rotate/configuration.rb +312 -0
- data/lib/rb.rotate/directory.rb +201 -0
- data/lib/rb.rotate/dispatcher.rb +112 -0
- data/lib/rb.rotate/file.rb +174 -0
- data/lib/rb.rotate/hook.rb +135 -0
- data/lib/rb.rotate/install/defaults.yaml.initial +25 -0
- data/lib/rb.rotate/install/rotate.yaml.initial +349 -0
- data/lib/rb.rotate/log.rb +80 -0
- data/lib/rb.rotate/mail.rb +40 -0
- data/lib/rb.rotate/reader.rb +94 -0
- data/lib/rb.rotate/state.rb +211 -0
- data/lib/rb.rotate/state/archive.rb +109 -0
- data/lib/rb.rotate/state/file.rb +139 -0
- data/lib/rb.rotate/storage.rb +208 -0
- data/lib/rb.rotate/storage/entry.rb +120 -0
- data/lib/rb.rotate/storage/item.rb +415 -0
- data/rb.rotate.gemspec +85 -0
- metadata +153 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module RbRotate
|
5
|
+
|
6
|
+
##
|
7
|
+
# Represents hook.
|
8
|
+
#
|
9
|
+
|
10
|
+
class Hook
|
11
|
+
|
12
|
+
##
|
13
|
+
# Holds name of the hook.
|
14
|
+
#
|
15
|
+
|
16
|
+
@name
|
17
|
+
|
18
|
+
##
|
19
|
+
# Holds data of the hook.
|
20
|
+
#
|
21
|
+
|
22
|
+
@data
|
23
|
+
|
24
|
+
##
|
25
|
+
# Holds arguments of the hook.
|
26
|
+
#
|
27
|
+
|
28
|
+
@arguments
|
29
|
+
|
30
|
+
##
|
31
|
+
# Hold variables for the hook.
|
32
|
+
#
|
33
|
+
|
34
|
+
@variables
|
35
|
+
|
36
|
+
##
|
37
|
+
# Constructor.
|
38
|
+
#
|
39
|
+
|
40
|
+
def initialize(name, arguments = nil, variables = { })
|
41
|
+
@name = name
|
42
|
+
@arguments = self.parse_arguments(arguments)
|
43
|
+
@variables = variables
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Parses "arguments line".
|
48
|
+
#
|
49
|
+
|
50
|
+
def parse_arguments(string)
|
51
|
+
if not string.nil?
|
52
|
+
string.split(":")
|
53
|
+
else
|
54
|
+
[]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Runs hook.
|
60
|
+
#
|
61
|
+
|
62
|
+
def run!
|
63
|
+
# Gets commans
|
64
|
+
command = self.command.dup
|
65
|
+
|
66
|
+
# Adds arguments
|
67
|
+
self.expand_arguments(command)
|
68
|
+
|
69
|
+
# Adds variables
|
70
|
+
self.expand_variables(command)
|
71
|
+
|
72
|
+
# Runs it
|
73
|
+
pipe = ::File.popen(command)
|
74
|
+
pipe.eof? # ask for EOF causes waiting for terminating the pipe process
|
75
|
+
|
76
|
+
result = pipe.read
|
77
|
+
pipe.close()
|
78
|
+
|
79
|
+
# Parses and returns result
|
80
|
+
return self.parse_result(result)
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Expands arguments.
|
85
|
+
#
|
86
|
+
|
87
|
+
def expand_arguments(command)
|
88
|
+
@arguments.each_index do |i|
|
89
|
+
arg = arguments[i]
|
90
|
+
command.gsub! "%" << i.to_s, '"' << arg << '"'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Expands variables.
|
96
|
+
#
|
97
|
+
|
98
|
+
def expand_variables(command)
|
99
|
+
@variables.each_pair do |name, value|
|
100
|
+
command.gsub! "%" << name, '"' << value << '"'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Parses result.
|
106
|
+
#
|
107
|
+
|
108
|
+
def parse_result(result)
|
109
|
+
if result.strip.empty?
|
110
|
+
return { }
|
111
|
+
end
|
112
|
+
|
113
|
+
result = YAML.load(result)
|
114
|
+
if not result.kind_of? Hash
|
115
|
+
result = { }
|
116
|
+
log "Warning: result of hook '" << @name.to_s << "' wasn't YAML collection. Ignored."
|
117
|
+
end
|
118
|
+
|
119
|
+
return result
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# Gets command.
|
124
|
+
#
|
125
|
+
|
126
|
+
def command
|
127
|
+
command = Configuration::get.hooks[@name]
|
128
|
+
if command.nil?
|
129
|
+
raise Exception::new("Invalid hook: " << @name.to_s)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# YAML
|
2
|
+
|
3
|
+
# Contains defaults for the configuration file.
|
4
|
+
# You SHOULDN'T need edit it.
|
5
|
+
|
6
|
+
paths:
|
7
|
+
state file: /var/lib/rb.rotate.status
|
8
|
+
defaults file: %%configuration/defaults.yaml
|
9
|
+
log file: /var/log/rb.rotate.log
|
10
|
+
|
11
|
+
dirs:
|
12
|
+
default:
|
13
|
+
directory: /var/log
|
14
|
+
recursive: yes
|
15
|
+
follow: true
|
16
|
+
storage: /var/log/archive
|
17
|
+
compress: yes
|
18
|
+
decompress: yes
|
19
|
+
rotate: 5
|
20
|
+
period: weekly
|
21
|
+
max size: 20M
|
22
|
+
mail: root@localhost
|
23
|
+
recycle: remove
|
24
|
+
identifier: numeric
|
25
|
+
action: move + create
|
@@ -0,0 +1,349 @@
|
|
1
|
+
# YAML
|
2
|
+
|
3
|
+
paths:
|
4
|
+
|
5
|
+
##
|
6
|
+
# Location of the state file (database about log rotation).
|
7
|
+
#
|
8
|
+
# Default value:
|
9
|
+
# /var/lib/rb.rotate.status
|
10
|
+
#
|
11
|
+
|
12
|
+
state file: /var/lib/rb.rotate.status
|
13
|
+
|
14
|
+
##
|
15
|
+
# Contains location of the file with default values. Content of this
|
16
|
+
# file is merged with this file. You sholdn't need edit it.
|
17
|
+
#
|
18
|
+
# Default value:
|
19
|
+
# %%configuration/defaults.yaml
|
20
|
+
#
|
21
|
+
|
22
|
+
defaults file: %%configuration/defaults.yaml
|
23
|
+
|
24
|
+
##
|
25
|
+
# Contains path to log file.
|
26
|
+
#
|
27
|
+
# Default value:
|
28
|
+
# /var/log/rb.rotate.log
|
29
|
+
#
|
30
|
+
|
31
|
+
log file: /var/log/rb.rotate.log
|
32
|
+
|
33
|
+
hooks:
|
34
|
+
# something: /path/to/some/script %filepath
|
35
|
+
|
36
|
+
dirs:
|
37
|
+
|
38
|
+
##
|
39
|
+
# Default directory must be set.
|
40
|
+
#
|
41
|
+
|
42
|
+
default:
|
43
|
+
|
44
|
+
##
|
45
|
+
# Directory from which will be logs archived. Recursive
|
46
|
+
# parameter says if it will be performed in subdirs.
|
47
|
+
#
|
48
|
+
# Default value:
|
49
|
+
# /var/log
|
50
|
+
#
|
51
|
+
|
52
|
+
directory: /var/log
|
53
|
+
|
54
|
+
##
|
55
|
+
# Defines inheritance. Options missing in the directory settings
|
56
|
+
# are then inherited from the parent directory.
|
57
|
+
#
|
58
|
+
# Default value:
|
59
|
+
# nothing
|
60
|
+
#
|
61
|
+
|
62
|
+
#parent:
|
63
|
+
|
64
|
+
##
|
65
|
+
# Says if archiving will be performed in subdirs of the
|
66
|
+
# 'directory' too. It's boolean value, but third value is 'flat'
|
67
|
+
# which means, files from subdirs will be archived without
|
68
|
+
# respecting the old structure directly to the 'archive'
|
69
|
+
# directory. In otherwise, original subdirectory structure will
|
70
|
+
# be respected.
|
71
|
+
#
|
72
|
+
# Possible values:
|
73
|
+
# - yes
|
74
|
+
# - no
|
75
|
+
# - flat
|
76
|
+
#
|
77
|
+
# Default value:
|
78
|
+
# yes
|
79
|
+
#
|
80
|
+
|
81
|
+
recursive: yes
|
82
|
+
|
83
|
+
##
|
84
|
+
# Says, it should follow symbolic links by transparent way. In
|
85
|
+
# storage, they will be handled as normal files and dirs. If
|
86
|
+
# false, they will be silently ignored.
|
87
|
+
#
|
88
|
+
# Default value:
|
89
|
+
# yes
|
90
|
+
#
|
91
|
+
|
92
|
+
follow: yes
|
93
|
+
|
94
|
+
##
|
95
|
+
# Directory to which will be logs archived.
|
96
|
+
#
|
97
|
+
# Default value:
|
98
|
+
# /var/log/archive
|
99
|
+
#
|
100
|
+
|
101
|
+
storage: /var/log/archive
|
102
|
+
|
103
|
+
##
|
104
|
+
# Says which command use for compressing the log. It must
|
105
|
+
# support the same base syntax and '<command> <file>' order
|
106
|
+
# as gzip and bzip2. You can specify it both as path with
|
107
|
+
# parameters or simply shell command. Uses gzip --best as
|
108
|
+
# default if set to 'yes'.
|
109
|
+
#
|
110
|
+
# It's also necessary specify the extension because without it
|
111
|
+
# rotate cannot detect compressed filenames. If you change
|
112
|
+
# compression method, all archived logs will be recompressed
|
113
|
+
# during next rotation.
|
114
|
+
#
|
115
|
+
# Default value:
|
116
|
+
# no
|
117
|
+
#
|
118
|
+
# Possible values:
|
119
|
+
# [<command>, <extension>]
|
120
|
+
# yes
|
121
|
+
# no
|
122
|
+
#
|
123
|
+
|
124
|
+
compress: yes
|
125
|
+
|
126
|
+
##
|
127
|
+
# Says which command use for decompression. It expects the same
|
128
|
+
# base syntax as gunzip or bunzip2. Uses gunzip as default if
|
129
|
+
# set to 'yes'.
|
130
|
+
#
|
131
|
+
# Be warn, decompress option must be synchronized with the
|
132
|
+
# compress option. Logically, if you set rotate up for
|
133
|
+
# compressing the logs, you must temporarily decompress them in
|
134
|
+
# archive before appending content to them or mailing them.
|
135
|
+
# If you turn off the compressing without decompressing enabled,
|
136
|
+
# it will cause damaged archive, of sure.
|
137
|
+
#
|
138
|
+
# Default value:
|
139
|
+
# no
|
140
|
+
#
|
141
|
+
# Possible values:
|
142
|
+
# <command>
|
143
|
+
# yes
|
144
|
+
# no
|
145
|
+
#
|
146
|
+
|
147
|
+
decompress: yes
|
148
|
+
|
149
|
+
##
|
150
|
+
# Says logs from which period it will keep accroding to 'type'
|
151
|
+
# option. So for example rotate settings '5' of the type
|
152
|
+
# 'weekly' means it will keep logs from five weeks.
|
153
|
+
#
|
154
|
+
# Default value:
|
155
|
+
# 5
|
156
|
+
#
|
157
|
+
|
158
|
+
rotate: 5
|
159
|
+
|
160
|
+
##
|
161
|
+
# Says how old should be log for archiving and in combination
|
162
|
+
# with 'rotate' option how old should be logs in archive
|
163
|
+
# maximally. (Simply period * rotate.)
|
164
|
+
#
|
165
|
+
# In contrast to classical logrotate, you can enter wide range
|
166
|
+
# of values. Firstly 'yearly', 'monthly' etc. where are their
|
167
|
+
# sense probably clear and secondly in format:
|
168
|
+
# <number> <period>
|
169
|
+
#
|
170
|
+
# So for example '2 weeks' or '5 days'. The smallest interval
|
171
|
+
# in this format is second, so you can define for example little
|
172
|
+
# obscure setting '2 seconds' or so.
|
173
|
+
#
|
174
|
+
# Be warn, if you will really use seconds with combination of
|
175
|
+
# date identifier of the archived files, default identifier
|
176
|
+
# format includes minutes only, so without changing it there is
|
177
|
+
# danger of rewritting the archived files.
|
178
|
+
#
|
179
|
+
# Default value:
|
180
|
+
# weekly
|
181
|
+
#
|
182
|
+
# Possible values:
|
183
|
+
# - yearly
|
184
|
+
# - monthly
|
185
|
+
# - weekly
|
186
|
+
# - daily
|
187
|
+
# - hourly
|
188
|
+
# - <number> years
|
189
|
+
# - <number> months
|
190
|
+
# - <number> weeks
|
191
|
+
# - <number> days
|
192
|
+
# - <number> hours
|
193
|
+
# - <number> minutes
|
194
|
+
# - <number> seconds
|
195
|
+
#
|
196
|
+
|
197
|
+
period: weekly
|
198
|
+
|
199
|
+
##
|
200
|
+
# Guards maximal size of the log. Log is bigger than this value,
|
201
|
+
# rotates it. But it keeps other archived logs lifetime, so
|
202
|
+
# although log has been rotated prematurely and number of logs
|
203
|
+
# in archive is bigger then 'rotate' settings, it will keep all
|
204
|
+
# because 'rotate' settings means only number of 'type' units
|
205
|
+
# for keeping the log, nothing more.
|
206
|
+
#
|
207
|
+
# You can use base units here: 'K', 'M' and 'G' which mean
|
208
|
+
# appropriate quantity of kilobytes, megabytes and gigabytes.
|
209
|
+
#
|
210
|
+
# Default value:
|
211
|
+
# 20M
|
212
|
+
#
|
213
|
+
|
214
|
+
max size: 20M
|
215
|
+
|
216
|
+
##
|
217
|
+
# Says to which e-mail address send recycled log or eventually
|
218
|
+
# the undefined mail action result.
|
219
|
+
#
|
220
|
+
# Default value:
|
221
|
+
# nothig
|
222
|
+
#
|
223
|
+
|
224
|
+
mail: root@localhost
|
225
|
+
|
226
|
+
##
|
227
|
+
# Says how to recycle mail removed from archive. It can be
|
228
|
+
# removed or removed and mailed to mail specified in 'mail'
|
229
|
+
# option. If 'no' or 'keep' option set, old archived logs are
|
230
|
+
# kept forever.
|
231
|
+
#
|
232
|
+
# Default value:
|
233
|
+
# remove
|
234
|
+
#
|
235
|
+
# Possible values:
|
236
|
+
# remove
|
237
|
+
# mail
|
238
|
+
# keep
|
239
|
+
# no
|
240
|
+
#
|
241
|
+
|
242
|
+
recycle: remove
|
243
|
+
|
244
|
+
##
|
245
|
+
# Says which type of archive distinguisher rotate will use.
|
246
|
+
# You can state the 'numeric' identifier, then increasing number
|
247
|
+
# will be used, or specify the string in date format syntax.
|
248
|
+
#
|
249
|
+
# Date formatting directives are following:
|
250
|
+
#
|
251
|
+
# %a - The abbreviated weekday name (``Sun'')
|
252
|
+
# %A - The full weekday name (``Sunday'')
|
253
|
+
# %b - The abbreviated month name (``Jan'')
|
254
|
+
# %B - The full month name (``January'')
|
255
|
+
# %c - The preferred local date and time representation
|
256
|
+
# %d - Day of the month (01..31)
|
257
|
+
# %H - Hour of the day, 24-hour clock (00..23)
|
258
|
+
# %I - Hour of the day, 12-hour clock (01..12)
|
259
|
+
# %j - Day of the year (001..366)
|
260
|
+
# %m - Month of the year (01..12)
|
261
|
+
# %M - Minute of the hour (00..59)
|
262
|
+
# %p - Meridian indicator (``AM'' or ``PM'')
|
263
|
+
# %S - Second of the minute (00..60)
|
264
|
+
# %U - Week number of the current year, starting with the
|
265
|
+
# first Sunday as the first day of the first week (00..53)
|
266
|
+
# %W - Week number of the current year, starting with the
|
267
|
+
# first Monday as the first day of the first week (00..53)
|
268
|
+
# %w - Day of the week (Sunday is 0, 0..6)
|
269
|
+
# %x - Preferred representation for the date alone, no time
|
270
|
+
# %X - Preferred representation for the time alone, no date
|
271
|
+
# %y - Year without a century (00..99)
|
272
|
+
# %Y - Year with century
|
273
|
+
# %Z - Time zone name
|
274
|
+
# %% - Literal ``%'' character
|
275
|
+
#
|
276
|
+
# If you type simply 'date', the following format will be used:
|
277
|
+
# %Y%m%d.%H%M
|
278
|
+
#
|
279
|
+
# Generally are supported all directives as listed in:
|
280
|
+
# http://ruby-doc.org/core/classes/Time.html#M000298
|
281
|
+
#
|
282
|
+
# Default value:
|
283
|
+
# numeric
|
284
|
+
#
|
285
|
+
# Possible values:
|
286
|
+
# numeric
|
287
|
+
# date
|
288
|
+
# <some formatting string>
|
289
|
+
#
|
290
|
+
|
291
|
+
identifier: numeric
|
292
|
+
|
293
|
+
##
|
294
|
+
# Says by which actions archive. Some daemons keep logs open, so
|
295
|
+
# there is necessary to copy the old log and truncate the file.
|
296
|
+
#
|
297
|
+
# One additional option is 'append' which orders appending the
|
298
|
+
# log to existing file. It has sense, of sure, only if the
|
299
|
+
# 'identifier' option is set by appropriate way, so filename in
|
300
|
+
# archive storage is static. Be warn, if you use compression,
|
301
|
+
# file will be recompressed in the whole if this action applied.
|
302
|
+
#
|
303
|
+
# 'Mail' action will mail log to specified address. If its
|
304
|
+
# argument is omitted, it will use argument from 'mail' setting.
|
305
|
+
#
|
306
|
+
# Be warn, this option works by "programmable" way. Tokens are
|
307
|
+
# evaluated in the order and without thinking about the right sense.
|
308
|
+
# So for example 'copy + move' will cause error because of moving
|
309
|
+
# the log to the existing file from previous copying, or
|
310
|
+
# 'truncate + copy' will truncate the file and thereafter copy empty
|
311
|
+
# file to archive location which probably isn't the required
|
312
|
+
# behaviour.
|
313
|
+
#
|
314
|
+
# It's possible to create chains, it isn't limited by number of two
|
315
|
+
# operations. Multiline can be achieved by standard YAML syntax.
|
316
|
+
# Chains are very useful for hooks.
|
317
|
+
#
|
318
|
+
# HOOKS
|
319
|
+
#
|
320
|
+
# But you can use hooks. Hook will get path to the file
|
321
|
+
# generated by preceding built-in operation as parameter
|
322
|
+
# %filepath, so it will get for example path to new file in
|
323
|
+
# archive in case of 'copy' or 'move' or name of the old file
|
324
|
+
# after 'truncate' or 'create'. Hook placed just after
|
325
|
+
# another hook will get parameters defined by YAML encoded
|
326
|
+
# hash array.
|
327
|
+
#
|
328
|
+
# Parameters are kept through the chain of actions, they are
|
329
|
+
# only overwritten by each action, so if action one will generate
|
330
|
+
# some argument and preceding action has generated another two
|
331
|
+
# arguments, these two arguments will be available for hooks
|
332
|
+
# after the action one too and the third argument will be
|
333
|
+
# available with new value set by action one.
|
334
|
+
#
|
335
|
+
#
|
336
|
+
# Possible values:
|
337
|
+
# - move
|
338
|
+
# - append
|
339
|
+
# - create
|
340
|
+
# - remove
|
341
|
+
# - truncate
|
342
|
+
# - mail:<e-mail>
|
343
|
+
# - hook:<hook name>
|
344
|
+
#
|
345
|
+
# Default value:
|
346
|
+
# move + create
|
347
|
+
#
|
348
|
+
|
349
|
+
action: move + create
|