backup 4.4.1 → 5.0.0.beta.3
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 +4 -4
- data/LICENSE +19 -0
- data/README.md +13 -9
- data/bin/docker_test +24 -0
- data/lib/backup/archive.rb +31 -32
- data/lib/backup/binder.rb +2 -6
- data/lib/backup/cleaner.rb +14 -18
- data/lib/backup/cli.rb +104 -108
- data/lib/backup/cloud_io/base.rb +4 -7
- data/lib/backup/cloud_io/cloud_files.rb +60 -62
- data/lib/backup/cloud_io/s3.rb +69 -76
- data/lib/backup/compressor/base.rb +4 -7
- data/lib/backup/compressor/bzip2.rb +3 -7
- data/lib/backup/compressor/custom.rb +2 -6
- data/lib/backup/compressor/gzip.rb +16 -17
- data/lib/backup/config/dsl.rb +16 -17
- data/lib/backup/config/helpers.rb +10 -16
- data/lib/backup/config.rb +17 -18
- data/lib/backup/database/base.rb +22 -21
- data/lib/backup/database/mongodb.rb +36 -37
- data/lib/backup/database/mysql.rb +40 -41
- data/lib/backup/database/openldap.rb +8 -10
- data/lib/backup/database/postgresql.rb +29 -30
- data/lib/backup/database/redis.rb +27 -30
- data/lib/backup/database/riak.rb +15 -18
- data/lib/backup/database/sqlite.rb +4 -6
- data/lib/backup/encryptor/base.rb +2 -4
- data/lib/backup/encryptor/gpg.rb +49 -59
- data/lib/backup/encryptor/open_ssl.rb +11 -14
- data/lib/backup/errors.rb +7 -12
- data/lib/backup/logger/console.rb +5 -8
- data/lib/backup/logger/fog_adapter.rb +2 -6
- data/lib/backup/logger/logfile.rb +10 -12
- data/lib/backup/logger/syslog.rb +2 -4
- data/lib/backup/logger.rb +16 -18
- data/lib/backup/model.rb +33 -40
- data/lib/backup/notifier/base.rb +24 -26
- data/lib/backup/notifier/campfire.rb +9 -11
- data/lib/backup/notifier/command.rb +0 -3
- data/lib/backup/notifier/datadog.rb +9 -12
- data/lib/backup/notifier/flowdock.rb +13 -17
- data/lib/backup/notifier/hipchat.rb +11 -13
- data/lib/backup/notifier/http_post.rb +11 -14
- data/lib/backup/notifier/mail.rb +42 -59
- data/lib/backup/notifier/nagios.rb +5 -9
- data/lib/backup/notifier/pagerduty.rb +10 -12
- data/lib/backup/notifier/prowl.rb +15 -15
- data/lib/backup/notifier/pushover.rb +7 -10
- data/lib/backup/notifier/ses.rb +34 -16
- data/lib/backup/notifier/slack.rb +39 -40
- data/lib/backup/notifier/twitter.rb +2 -5
- data/lib/backup/notifier/zabbix.rb +11 -14
- data/lib/backup/package.rb +5 -9
- data/lib/backup/packager.rb +16 -17
- data/lib/backup/pipeline.rb +17 -21
- data/lib/backup/splitter.rb +8 -11
- data/lib/backup/storage/base.rb +5 -8
- data/lib/backup/storage/cloud_files.rb +21 -23
- data/lib/backup/storage/cycler.rb +10 -15
- data/lib/backup/storage/dropbox.rb +15 -21
- data/lib/backup/storage/ftp.rb +14 -10
- data/lib/backup/storage/local.rb +5 -8
- data/lib/backup/storage/qiniu.rb +8 -8
- data/lib/backup/storage/rsync.rb +24 -26
- data/lib/backup/storage/s3.rb +27 -28
- data/lib/backup/storage/scp.rb +10 -12
- data/lib/backup/storage/sftp.rb +10 -12
- data/lib/backup/syncer/base.rb +5 -8
- data/lib/backup/syncer/cloud/base.rb +27 -30
- data/lib/backup/syncer/cloud/cloud_files.rb +16 -18
- data/lib/backup/syncer/cloud/local_file.rb +5 -8
- data/lib/backup/syncer/cloud/s3.rb +23 -24
- data/lib/backup/syncer/rsync/base.rb +6 -10
- data/lib/backup/syncer/rsync/local.rb +1 -5
- data/lib/backup/syncer/rsync/pull.rb +6 -10
- data/lib/backup/syncer/rsync/push.rb +18 -22
- data/lib/backup/template.rb +9 -14
- data/lib/backup/utilities.rb +78 -69
- data/lib/backup/version.rb +1 -3
- data/lib/backup.rb +74 -78
- metadata +107 -676
data/lib/backup/encryptor/gpg.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
2
|
module Encryptor
|
5
3
|
##
|
@@ -104,7 +102,7 @@ module Backup
|
|
104
102
|
attr_reader :mode
|
105
103
|
def mode=(mode)
|
106
104
|
@mode = mode.to_sym
|
107
|
-
raise Error, "'#{
|
105
|
+
raise Error, "'#{@mode}' is not a valid mode." unless MODES.include?(@mode)
|
108
106
|
end
|
109
107
|
|
110
108
|
##
|
@@ -411,11 +409,10 @@ module Backup
|
|
411
409
|
prepare
|
412
410
|
|
413
411
|
if mode_options.empty?
|
414
|
-
raise Error, "Encryption could not be performed for mode '#{
|
412
|
+
raise Error, "Encryption could not be performed for mode '#{mode}'"
|
415
413
|
end
|
416
414
|
|
417
|
-
yield "#{
|
418
|
-
|
415
|
+
yield "#{utility(:gpg)} #{base_options} #{mode_options}", ".gpg"
|
419
416
|
ensure
|
420
417
|
cleanup
|
421
418
|
end
|
@@ -426,7 +423,7 @@ module Backup
|
|
426
423
|
# Remove any temporary directories and reset all instance variables.
|
427
424
|
#
|
428
425
|
def prepare
|
429
|
-
FileUtils.rm_rf(@tempdirs, :
|
426
|
+
FileUtils.rm_rf(@tempdirs, secure: true) if @tempdirs
|
430
427
|
@tempdirs = []
|
431
428
|
@base_options = nil
|
432
429
|
@mode_options = nil
|
@@ -444,12 +441,12 @@ module Backup
|
|
444
441
|
#
|
445
442
|
def base_options
|
446
443
|
@base_options ||= begin
|
447
|
-
opts = [
|
444
|
+
opts = ["--no-tty"]
|
448
445
|
path = setup_gpg_homedir
|
449
|
-
opts << "--homedir '#{
|
446
|
+
opts << "--homedir '#{path}'" if path
|
450
447
|
path = setup_gpg_config
|
451
|
-
opts << "--options '#{
|
452
|
-
opts.join(
|
448
|
+
opts << "--options '#{path}'" if path
|
449
|
+
opts.join(" ")
|
453
450
|
end
|
454
451
|
end
|
455
452
|
|
@@ -470,18 +467,17 @@ module Backup
|
|
470
467
|
path = File.expand_path(gpg_homedir)
|
471
468
|
FileUtils.mkdir_p(path)
|
472
469
|
FileUtils.chown(Config.user, nil, path)
|
473
|
-
FileUtils.chmod(
|
470
|
+
FileUtils.chmod(0o700, path)
|
474
471
|
|
475
|
-
unless %w
|
476
|
-
all? {|name| File.exist? File.join(path, name) }
|
477
|
-
run("#{
|
472
|
+
unless %w[pubring.gpg secring.gpg trustdb.gpg]
|
473
|
+
.all? { |name| File.exist? File.join(path, name) }
|
474
|
+
run("#{utility(:gpg)} --homedir '#{path}' -K 2>&1 >/dev/null")
|
478
475
|
end
|
479
476
|
|
480
477
|
path
|
481
|
-
|
482
478
|
rescue => err
|
483
|
-
raise Error.wrap
|
484
|
-
|
479
|
+
raise Error.wrap \
|
480
|
+
err, "Failed to create or set permissions for #gpg_homedir"
|
485
481
|
end
|
486
482
|
|
487
483
|
##
|
@@ -501,16 +497,15 @@ module Backup
|
|
501
497
|
def setup_gpg_config
|
502
498
|
return false unless gpg_config
|
503
499
|
|
504
|
-
dir = Dir.mktmpdir(
|
500
|
+
dir = Dir.mktmpdir("backup-gpg_config", Config.tmp_path)
|
505
501
|
@tempdirs << dir
|
506
|
-
file = Tempfile.open(
|
507
|
-
file.write gpg_config.gsub(/^[[:blank:]]+/,
|
502
|
+
file = Tempfile.open("backup-gpg_config", dir)
|
503
|
+
file.write gpg_config.gsub(/^[[:blank:]]+/, "")
|
508
504
|
file.close
|
509
505
|
|
510
506
|
check_gpg_config(file.path)
|
511
507
|
|
512
508
|
file.path
|
513
|
-
|
514
509
|
rescue => err
|
515
510
|
cleanup
|
516
511
|
raise Error.wrap(err, "Error creating temporary file for #gpg_config.")
|
@@ -524,7 +519,7 @@ module Backup
|
|
524
519
|
#
|
525
520
|
def check_gpg_config(path)
|
526
521
|
ret = run(
|
527
|
-
"#{
|
522
|
+
"#{utility(:gpg)} --options '#{path}' --gpgconf-test 2>&1"
|
528
523
|
).chomp
|
529
524
|
raise ret unless ret.empty?
|
530
525
|
end
|
@@ -537,7 +532,7 @@ module Backup
|
|
537
532
|
@mode_options ||= begin
|
538
533
|
s_opts = symmetric_options if mode != :asymmetric
|
539
534
|
a_opts = asymmetric_options if mode != :symmetric
|
540
|
-
[s_opts, a_opts].compact.join(
|
535
|
+
[s_opts, a_opts].compact.join(" ")
|
541
536
|
end
|
542
537
|
end
|
543
538
|
|
@@ -555,7 +550,7 @@ module Backup
|
|
555
550
|
end
|
556
551
|
|
557
552
|
if path && File.exist?(path)
|
558
|
-
"-c --passphrase-file '#{
|
553
|
+
"-c --passphrase-file '#{path}'"
|
559
554
|
else
|
560
555
|
Logger.warn("Symmetric encryption options could not be set.")
|
561
556
|
nil
|
@@ -570,14 +565,13 @@ module Backup
|
|
570
565
|
def setup_passphrase_file
|
571
566
|
return false if passphrase.to_s.empty?
|
572
567
|
|
573
|
-
dir = Dir.mktmpdir(
|
568
|
+
dir = Dir.mktmpdir("backup-gpg_passphrase", Config.tmp_path)
|
574
569
|
@tempdirs << dir
|
575
|
-
file = Tempfile.open(
|
570
|
+
file = Tempfile.open("backup-gpg_passphrase", dir)
|
576
571
|
file.write passphrase.to_s
|
577
572
|
file.close
|
578
573
|
|
579
574
|
file.path
|
580
|
-
|
581
575
|
rescue => err
|
582
576
|
Logger.warn Error.wrap(err, "Error creating temporary passphrase file.")
|
583
577
|
false
|
@@ -595,7 +589,7 @@ module Backup
|
|
595
589
|
else
|
596
590
|
# skip trust database checks
|
597
591
|
"-e --trust-model always " +
|
598
|
-
|
592
|
+
user_recipients.map { |r| "-r '#{r}'" }.join(" ")
|
599
593
|
end
|
600
594
|
end
|
601
595
|
|
@@ -622,9 +616,8 @@ module Backup
|
|
622
616
|
# will log a warning and return nil if the import fails
|
623
617
|
import_key(identifier, key)
|
624
618
|
else
|
625
|
-
Logger.warn
|
626
|
-
"No public key was found in #keys for '#{
|
627
|
-
)
|
619
|
+
Logger.warn \
|
620
|
+
"No public key was found in #keys for '#{identifier}'"
|
628
621
|
nil
|
629
622
|
end
|
630
623
|
end
|
@@ -640,10 +633,11 @@ module Backup
|
|
640
633
|
def user_keys
|
641
634
|
@user_keys ||= begin
|
642
635
|
_keys = keys || {}
|
643
|
-
ret = Hash[_keys.map {|k,v| [clean_identifier(k), v] }]
|
644
|
-
|
645
|
-
|
646
|
-
|
636
|
+
ret = Hash[_keys.map { |k, v| [clean_identifier(k), v] }]
|
637
|
+
if ret.keys.count != _keys.keys.count
|
638
|
+
Logger.warn \
|
639
|
+
"Duplicate public key identifiers were detected in #keys."
|
640
|
+
end
|
647
641
|
ret
|
648
642
|
end
|
649
643
|
end
|
@@ -654,8 +648,8 @@ module Backup
|
|
654
648
|
# and wrap email addresses in <> to perform exact matching.
|
655
649
|
#
|
656
650
|
def clean_identifier(str)
|
657
|
-
str = str.to_s.gsub(/[[:blank:]]+/,
|
658
|
-
str =~ /@/ ? "<#{
|
651
|
+
str = str.to_s.gsub(/[[:blank:]]+/, "")
|
652
|
+
str =~ /@/ ? "<#{str.gsub(/(<|>)/, "")}>" : str.upcase
|
659
653
|
end
|
660
654
|
|
661
655
|
##
|
@@ -664,22 +658,20 @@ module Backup
|
|
664
658
|
# Note that errors raised by Cli::Helpers#run may also be rescued here.
|
665
659
|
#
|
666
660
|
def import_key(identifier, key)
|
667
|
-
file = Tempfile.open(
|
668
|
-
file.write(key.gsub(/^[[:blank:]]+/,
|
661
|
+
file = Tempfile.open("backup-gpg_import", Config.tmp_path)
|
662
|
+
file.write(key.gsub(/^[[:blank:]]+/, ""))
|
669
663
|
file.close
|
670
|
-
ret = run(
|
671
|
-
"
|
672
|
-
"--keyid-format 0xlong --import '#{ file.path }' 2>&1"
|
673
|
-
)
|
664
|
+
ret = run "#{utility(:gpg)} #{base_options} " \
|
665
|
+
"--keyid-format 0xlong --import '#{file.path}' 2>&1"
|
674
666
|
file.delete
|
675
667
|
|
676
668
|
keyid = ret.match(/ 0x(\w{16})/).to_a[1]
|
677
|
-
raise "GPG Returned:\n#{
|
669
|
+
raise "GPG Returned:\n#{ret.gsub(/^\s*/, " ")}" unless keyid
|
678
670
|
keyid
|
679
|
-
|
680
671
|
rescue => err
|
681
672
|
Logger.warn Error.wrap(
|
682
|
-
|
673
|
+
err, "Public key import failed for '#{identifier}'"
|
674
|
+
)
|
683
675
|
nil
|
684
676
|
end
|
685
677
|
|
@@ -691,20 +683,17 @@ module Backup
|
|
691
683
|
def system_identifiers
|
692
684
|
@system_identifiers ||= begin
|
693
685
|
skip_key = false
|
694
|
-
data = run(
|
695
|
-
"#{ utility(:gpg) } #{ base_options } " +
|
686
|
+
data = run "#{utility(:gpg)} #{base_options} " \
|
696
687
|
"--with-colons --fixed-list-mode --fingerprint"
|
697
|
-
)
|
698
688
|
data.lines.map do |line|
|
699
689
|
line.strip!
|
700
690
|
|
701
691
|
# process public key record
|
702
692
|
if line =~ /^pub:/
|
703
|
-
validity, keyid, capabilities =
|
704
|
-
line.split(':').values_at(1, 4, 11)
|
693
|
+
validity, keyid, capabilities = line.split(":").values_at(1, 4, 11)
|
705
694
|
# skip keys marked as revoked ('r'), expired ('e'),
|
706
695
|
# invalid ('i') or disabled ('D')
|
707
|
-
if validity[0,1] =~ /(r|e|i)/ || capabilities =~ /D/
|
696
|
+
if validity[0, 1] =~ /(r|e|i)/ || capabilities =~ /D/
|
708
697
|
skip_key = true
|
709
698
|
next nil
|
710
699
|
else
|
@@ -714,26 +703,28 @@ module Backup
|
|
714
703
|
end
|
715
704
|
else
|
716
705
|
# wait for the next valid public key record
|
717
|
-
next
|
706
|
+
next if skip_key
|
718
707
|
|
719
708
|
# process UID records for the current public key
|
720
709
|
if line =~ /^uid:/
|
721
|
-
validity, userid = line.split(
|
710
|
+
validity, userid = line.split(":").values_at(1, 9)
|
722
711
|
# skip records marked as revoked ('r'), expired ('e')
|
723
712
|
# or invalid ('i')
|
724
713
|
if validity !~ /(r|e|i)/
|
725
714
|
# return the last email found in user id string,
|
726
715
|
# since this includes user supplied comments.
|
727
716
|
# return nil if no email found.
|
728
|
-
email
|
717
|
+
email = nil
|
718
|
+
str = userid
|
729
719
|
while match = str.match(/<.+?@.+?>/)
|
730
|
-
email
|
720
|
+
email = match[0]
|
721
|
+
str = match.post_match
|
731
722
|
end
|
732
723
|
next email
|
733
724
|
end
|
734
725
|
# return public key's fingerprint
|
735
726
|
elsif line =~ /^fpr:/
|
736
|
-
next line.split(
|
727
|
+
next line.split(":")[9]
|
737
728
|
end
|
738
729
|
|
739
730
|
nil # ignore any other lines
|
@@ -741,7 +732,6 @@ module Backup
|
|
741
732
|
end.flatten.compact
|
742
733
|
end
|
743
734
|
end
|
744
|
-
|
745
735
|
end
|
746
736
|
end
|
747
737
|
end
|
@@ -1,9 +1,6 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
2
|
module Encryptor
|
5
3
|
class OpenSSL < Base
|
6
|
-
|
7
4
|
##
|
8
5
|
# The password that'll be used to encrypt the backup. This
|
9
6
|
# password will be required to decrypt the backup later on.
|
@@ -42,7 +39,7 @@ module Backup
|
|
42
39
|
# so that any clean-up may be performed after the yield.
|
43
40
|
def encrypt_with
|
44
41
|
log!
|
45
|
-
yield "#{
|
42
|
+
yield "#{utility(:openssl)} #{options}", ".enc"
|
46
43
|
end
|
47
44
|
|
48
45
|
private
|
@@ -59,19 +56,19 @@ module Backup
|
|
59
56
|
# Always sets a password option, if even no password is given,
|
60
57
|
# but will prefer the password_file option if both are given.
|
61
58
|
def options
|
62
|
-
opts = [
|
63
|
-
opts <<
|
64
|
-
opts <<
|
59
|
+
opts = ["aes-256-cbc"]
|
60
|
+
opts << "-base64" if @base64
|
61
|
+
opts << "-salt" if @salt
|
65
62
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
63
|
+
opts <<
|
64
|
+
if @password_file.to_s.empty?
|
65
|
+
"-k #{Shellwords.escape(@password)}"
|
66
|
+
else
|
67
|
+
"-pass file:#{@password_file}"
|
68
|
+
end
|
71
69
|
|
72
|
-
opts.join(
|
70
|
+
opts.join(" ")
|
73
71
|
end
|
74
|
-
|
75
72
|
end
|
76
73
|
end
|
77
74
|
end
|
data/lib/backup/errors.rb
CHANGED
@@ -1,29 +1,25 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
|
-
|
5
2
|
# Provides cascading errors with formatted messages.
|
6
3
|
# See the specs for details.
|
7
4
|
module NestedExceptions
|
8
|
-
|
9
5
|
def self.included(klass)
|
10
|
-
klass.extend
|
6
|
+
klass.extend(Module.new do
|
11
7
|
def wrap(wrapped_exception, msg = nil)
|
12
8
|
new(msg, wrapped_exception)
|
13
9
|
end
|
14
|
-
|
10
|
+
end)
|
15
11
|
end
|
16
12
|
|
17
13
|
def initialize(obj = nil, wrapped_exception = nil)
|
18
14
|
@wrapped_exception = wrapped_exception
|
19
|
-
msg = (obj.respond_to?(:to_str) ? obj.to_str : obj.to_s)
|
20
|
-
|
21
|
-
msg = clean_name(self.class.name) + (msg.empty? ?
|
15
|
+
msg = (obj.respond_to?(:to_str) ? obj.to_str : obj.to_s)
|
16
|
+
.gsub(/^ */, " ").strip
|
17
|
+
msg = clean_name(self.class.name) + (msg.empty? ? "" : ": #{msg}")
|
22
18
|
|
23
19
|
if wrapped_exception
|
24
20
|
msg << "\n--- Wrapped Exception ---\n"
|
25
21
|
class_name = clean_name(wrapped_exception.class.name)
|
26
|
-
msg << class_name +
|
22
|
+
msg << class_name + ": " unless
|
27
23
|
wrapped_exception.message.start_with? class_name
|
28
24
|
msg << wrapped_exception.message
|
29
25
|
end
|
@@ -43,9 +39,8 @@ module Backup
|
|
43
39
|
private
|
44
40
|
|
45
41
|
def clean_name(name)
|
46
|
-
name.sub(/^Backup::/,
|
42
|
+
name.sub(/^Backup::/, "")
|
47
43
|
end
|
48
|
-
|
49
44
|
end
|
50
45
|
|
51
46
|
class Error < StandardError
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
2
|
class Logger
|
5
3
|
class Console
|
@@ -30,22 +28,21 @@ module Backup
|
|
30
28
|
end
|
31
29
|
|
32
30
|
COLORS = {
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
31
|
+
info: "\e[32m%s\e[0m", # green
|
32
|
+
warn: "\e[33m%s\e[0m", # yellow
|
33
|
+
error: "\e[31m%s\e[0m" # red
|
36
34
|
}
|
37
35
|
|
38
|
-
def initialize(
|
36
|
+
def initialize(_options = nil)
|
39
37
|
$stdout.sync = $stderr.sync = true
|
40
38
|
end
|
41
39
|
|
42
40
|
def log(message)
|
43
41
|
io = message.level == :info ? $stdout : $stderr
|
44
42
|
lines = message.formatted_lines
|
45
|
-
lines.map! {|line| COLORS[message.level] % line } if io.tty?
|
43
|
+
lines.map! { |line| COLORS[message.level] % line } if io.tty?
|
46
44
|
io.puts lines
|
47
45
|
end
|
48
|
-
|
49
46
|
end
|
50
47
|
end
|
51
48
|
end
|
@@ -1,14 +1,11 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# require only the logger
|
4
|
-
require
|
5
|
-
require
|
2
|
+
require "formatador"
|
3
|
+
require "fog/core/logger"
|
6
4
|
|
7
5
|
module Backup
|
8
6
|
class Logger
|
9
7
|
module FogAdapter
|
10
8
|
class << self
|
11
|
-
|
12
9
|
# Logged as :info so these won't generate warnings.
|
13
10
|
# This is mostly to keep STDOUT clean and to provide
|
14
11
|
# supplemental messages for our own warnings.
|
@@ -20,7 +17,6 @@ module Backup
|
|
20
17
|
def tty?
|
21
18
|
false
|
22
19
|
end
|
23
|
-
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
2
|
class Logger
|
5
3
|
class Logfile
|
@@ -60,7 +58,7 @@ module Backup
|
|
60
58
|
|
61
59
|
def initialize
|
62
60
|
@enabled = true
|
63
|
-
@log_path =
|
61
|
+
@log_path = ""
|
64
62
|
@max_bytes = 500_000
|
65
63
|
end
|
66
64
|
|
@@ -84,7 +82,7 @@ module Backup
|
|
84
82
|
end
|
85
83
|
|
86
84
|
def log(message)
|
87
|
-
File.open(@logfile,
|
85
|
+
File.open(@logfile, "a") { |f| f.puts message.formatted_lines }
|
88
86
|
end
|
89
87
|
|
90
88
|
private
|
@@ -95,17 +93,17 @@ module Backup
|
|
95
93
|
def setup_logfile
|
96
94
|
# strip any trailing '/' in case the user supplied this as part of
|
97
95
|
# an absolute path, so we can match it against File.expand_path()
|
98
|
-
path = @options.log_path.chomp(
|
96
|
+
path = @options.log_path.chomp("/")
|
99
97
|
if path.empty?
|
100
|
-
path = File.join(Backup::Config.root_path,
|
98
|
+
path = File.join(Backup::Config.root_path, "log")
|
101
99
|
elsif path != File.expand_path(path)
|
102
100
|
path = File.join(Backup::Config.root_path, path)
|
103
101
|
end
|
104
102
|
FileUtils.mkdir_p(path)
|
105
|
-
log_file = @options.log_file ||
|
103
|
+
log_file = @options.log_file || "backup.log"
|
106
104
|
path = File.join(path, log_file)
|
107
105
|
if File.exist?(path) && !File.writable?(path)
|
108
|
-
raise Error, "Log File at '#{
|
106
|
+
raise Error, "Log File at '#{path}' is not writable"
|
109
107
|
end
|
110
108
|
path
|
111
109
|
end
|
@@ -116,16 +114,16 @@ module Backup
|
|
116
114
|
return unless File.exist?(@logfile)
|
117
115
|
|
118
116
|
if File.stat(@logfile).size > @options.max_bytes
|
119
|
-
FileUtils.cp(@logfile, @logfile +
|
120
|
-
File.open(@logfile +
|
121
|
-
File.open(@logfile,
|
117
|
+
FileUtils.cp(@logfile, @logfile + "~")
|
118
|
+
File.open(@logfile + "~", "r") do |io_in|
|
119
|
+
File.open(@logfile, "w") do |io_out|
|
122
120
|
io_in.seek(-@options.max_bytes, IO::SEEK_END) && io_in.gets
|
123
121
|
while line = io_in.gets
|
124
122
|
io_out.puts line
|
125
123
|
end
|
126
124
|
end
|
127
125
|
end
|
128
|
-
FileUtils.rm_f(@logfile +
|
126
|
+
FileUtils.rm_f(@logfile + "~")
|
129
127
|
end
|
130
128
|
end
|
131
129
|
end
|
data/lib/backup/logger/syslog.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Backup
|
4
2
|
class Logger
|
5
3
|
class Syslog
|
@@ -81,7 +79,7 @@ module Backup
|
|
81
79
|
|
82
80
|
def initialize
|
83
81
|
@enabled = false
|
84
|
-
@ident =
|
82
|
+
@ident = "backup"
|
85
83
|
@options = ::Syslog::LOG_PID
|
86
84
|
@facility = ::Syslog::LOG_LOCAL0
|
87
85
|
@info = ::Syslog::LOG_INFO
|
@@ -108,7 +106,7 @@ module Backup
|
|
108
106
|
def log(message)
|
109
107
|
level = @options.send(message.level)
|
110
108
|
::Syslog.open(@options.ident, @options.options, @options.facility) do |s|
|
111
|
-
message.lines.each {|line| s.log(level,
|
109
|
+
message.lines.each { |line| s.log(level, "%s", line) }
|
112
110
|
end
|
113
111
|
end
|
114
112
|
end
|
data/lib/backup/logger.rb
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require 'backup/logger/syslog'
|
6
|
-
require 'backup/logger/fog_adapter'
|
1
|
+
require "backup/logger/console"
|
2
|
+
require "backup/logger/logfile"
|
3
|
+
require "backup/logger/syslog"
|
4
|
+
require "backup/logger/fog_adapter"
|
7
5
|
|
8
6
|
module Backup
|
9
7
|
class Logger
|
10
|
-
|
11
8
|
class Config
|
12
9
|
class Logger < Struct.new(:class, :options)
|
13
10
|
def enabled?
|
@@ -44,22 +41,22 @@ module Backup
|
|
44
41
|
# [YYYY/MM/DD HH:MM:SS][level] message line text
|
45
42
|
def formatted_lines
|
46
43
|
timestamp = time.strftime("%Y/%m/%d %H:%M:%S")
|
47
|
-
lines.map {|line| "[#{
|
44
|
+
lines.map { |line| "[#{timestamp}][#{level}] #{line}" }
|
48
45
|
end
|
49
46
|
|
50
47
|
def matches?(ignores)
|
51
48
|
text = lines.join("\n")
|
52
|
-
ignores.any?
|
49
|
+
ignores.any? do |obj|
|
53
50
|
obj.is_a?(Regexp) ? text.match(obj) : text.include?(obj)
|
54
|
-
|
51
|
+
end
|
55
52
|
end
|
56
53
|
end
|
57
54
|
|
58
55
|
class << self
|
59
56
|
extend Forwardable
|
60
57
|
def_delegators :logger,
|
61
|
-
|
62
|
-
|
58
|
+
:start!, :abort!, :info, :warn, :error,
|
59
|
+
:messages, :has_warnings?, :has_errors?
|
63
60
|
|
64
61
|
##
|
65
62
|
# Allows the Logger to be configured.
|
@@ -137,9 +134,9 @@ module Backup
|
|
137
134
|
# Sends a message to the Logger using the specified log level.
|
138
135
|
# +obj+ may be any Object that responds to #to_s (i.e. an Exception)
|
139
136
|
[:info, :warn, :error].each do |level|
|
140
|
-
define_method level
|
137
|
+
define_method level do |obj|
|
141
138
|
MUTEX.synchronize { log(obj, level) }
|
142
|
-
|
139
|
+
end
|
143
140
|
end
|
144
141
|
|
145
142
|
##
|
@@ -169,7 +166,7 @@ module Backup
|
|
169
166
|
@loggers << logger.class.new(logger.options) if logger.enabled?
|
170
167
|
end
|
171
168
|
messages.each do |message|
|
172
|
-
@loggers.each {|logger| logger.log(message) }
|
169
|
+
@loggers.each { |logger| logger.log(message) }
|
173
170
|
end
|
174
171
|
end
|
175
172
|
|
@@ -187,13 +184,14 @@ module Backup
|
|
187
184
|
def log(obj, level)
|
188
185
|
message = Message.new(Time.now.utc, level, obj.to_s.split("\n"))
|
189
186
|
|
190
|
-
|
191
|
-
|
187
|
+
if message.level == :warn && message.matches?(@config.ignores)
|
188
|
+
message.level = :info
|
189
|
+
end
|
192
190
|
@has_warnings ||= message.level == :warn
|
193
191
|
@has_errors ||= message.level == :error
|
194
192
|
|
195
193
|
messages << message
|
196
|
-
@loggers.each {|logger| logger.log(message) }
|
194
|
+
@loggers.each { |logger| logger.log(message) }
|
197
195
|
end
|
198
196
|
end
|
199
197
|
end
|