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