simple_rotate 1.0.0 → 1.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
  SHA1:
3
- metadata.gz: 57afd4b6d133d914743e6d548507323c5f6f9926
4
- data.tar.gz: a5a6cf55f8e7894d9c7c090a7f0b429161aad2c9
3
+ metadata.gz: 481428ce2f0316a88fabc15531a03bb722641a86
4
+ data.tar.gz: 482f5c5d2154f63ef017817941e049ed7078dff3
5
5
  SHA512:
6
- metadata.gz: 220d55fbab5182dcc7a767113c35b948c9d10c58f23b18e1fe66ff7b5570ebb550964aea5ed5df6f603585dfe2939049db366f51b59d9c4940c9f242badc3fc6
7
- data.tar.gz: f66d8796b8f5cb125541041a621363fdaba0431c81c47e666b43c65f0ed5274dea1a1aa6f5077a37a887242e8d60e63fc466d2e0ed155503847bcf09b5846ad8
6
+ metadata.gz: 50bdabad14095319c3caaeb70df3c5ed79b6a76d637ba7a44863fd644e018624c4afb43aa5f633635a86b5250a54b53ce7cb80d29c8663d4394dd50270f7207e
7
+ data.tar.gz: 80d19f35402ae0aabc0e099986b2dda5f68efe8b7f3b5f0228628a4c16229ecf24238e743f8068c4531324836270503b6c6e5beed3798a15a3630579cc66963e
@@ -1,1127 +1,6 @@
1
- # SimpleRotate - simple logger for ruby
2
- # @autor: Kazuya Hotta (nyanko)
1
+ # SimpleRotate
3
2
  #
4
- require "singleton"
5
- require "monitor"
6
-
7
- class SimpleRotate
8
- VERSION = "1.0.0"
9
- include Singleton
10
- include MonitorMixin
11
-
12
- #----------------
13
- # modlues
14
- #----------------
15
- module LogLevel
16
- LOG_LEVEL_5 = "FATAL"
17
- LOG_LEVEL_4 = "ERROR"
18
- LOG_LEVEL_3 = "WARN"
19
- LOG_LEVEL_2 = "INFO"
20
- LOG_LEVEL_1 = "DEBUG"
21
- LEVEL_ID_FATAL = 5
22
- LEVEL_ID_ERROR = 4
23
- LEVEL_ID_WARN = 3
24
- LEVEL_ID_INFO = 2
25
- LEVEL_ID_DEBUG = 1
26
- end
27
- include LogLevel
28
-
29
- module RotateTerm
30
- TERM_DAILY = 1
31
- TERM_WEEKLY = 7
32
- TERM_MONTHLY = 30
33
- end
34
- include RotateTerm
35
-
36
- module Validator
37
- def valid_file_name
38
- # stdout only
39
- if @file_name.is_a?(Symbol) && @file_name == :STDOUT
40
- @only_stdout = true
41
- return true
42
- end
43
-
44
- # not string
45
- if !@file_name.is_a?(String)
46
- SimpleRotate::Error.argv("file_name", @file_name)
47
- end
48
-
49
- # directory?
50
- if File.directory?(@file_name)
51
- msg = "ERROR => #{@file_name} is a Directory!"
52
- SimpleRotate::Error.warning(msg)
53
- SimpleRotate::Error.argv("file_name", @file_name)
54
- end
55
-
56
- return true
57
- end
58
-
59
- def valid_int(param, argv)
60
- if !argv.is_a?(Integer)
61
- SimpleRotate::Error.argv(param, argv)
62
-
63
- elsif argv < 0
64
- msg = %{You can't specify the negative value!}
65
- SimpleRotate::Error.warning(msg)
66
- SimpleRotate::Error.argv(param, argv)
67
- end
68
- end
69
-
70
- def valid_bool(param, argv)
71
- argv = true if argv == 1
72
- argv = false if argv == 0
73
- if !(argv.instance_of?(TrueClass) || argv.instance_of?(FalseClass))
74
- SimpleRotate::Error.argv(param, argv)
75
- end
76
- return true
77
- end
78
- end
79
- include Validator
80
-
81
- #----------------
82
- # classes
83
- #----------------
84
- #
85
- # error class for SimpleRotate
86
- #
87
- class Error < RuntimeError
88
- msg = "aborted the log file rotation process,"
89
- msg += " because an unexpected error has occured."
90
- ROTATION_FAILED = msg
91
-
92
- @@silence = false
93
-
94
- #
95
- # skip warning message
96
- #
97
- def self.silence
98
- @@silence = true
99
- end
100
-
101
- #
102
- # argument error
103
- #
104
- def self.argv(param, argv)
105
- msg = "'#{param}'='#{argv}' is invalid argument value!"
106
- self.throw_error(msg)
107
- end
108
-
109
- #
110
- # method missing
111
- #
112
- def self.missing(name)
113
- msg = "undifined method 'SimpleRotate##{name}'"
114
- self.throw_error(msg)
115
- end
116
-
117
- #
118
- # file open error
119
- #
120
- def self.open(name)
121
- msg = "Couldn't open a '#{name}'"
122
- self.throw_error(msg)
123
- end
124
-
125
- #
126
- # load error
127
- #
128
- def self.load(name)
129
- msg = "Couldn't load a '#{name}'"
130
- self.throw_error(msg)
131
- end
132
-
133
- #
134
- # exist error
135
- #
136
- def self.exist(name, type)
137
- msg = "Already exists this #{type} => '#{name}'"
138
- self.throw_error(msg)
139
- end
140
-
141
- #
142
- # warning - don't throw error
143
- #
144
- def self.warning(msg)
145
- warn "[WARNING] #{msg} - (SimpleRotate::Error)" if !@@silence
146
- end
147
-
148
- # @param msg string
149
- #
150
- def self.throw_error(msg)
151
- exeption = self.new(msg)
152
- warn exeption.message if !@@silence
153
- raise SimpleRotate::Error
154
- end
155
- end
156
-
157
- #
158
- # The module for the process safe
159
- # This module will be included by ProcessSync class
160
- #
161
- module ProcessSyncMixin
162
- @@scheduled_del_lockfile = false
163
- @@tempf_name = nil
164
- @@tempf = nil
165
-
166
- def locked?
167
- return false if !tempf_exists?
168
-
169
- # return false, if locked by another
170
- status = @@tempf.flock(File::LOCK_EX | File::LOCK_NB)
171
-
172
- return status == false
173
- end
174
-
175
- # lock the temp file
176
- def lock
177
- create_tempfile if !tempf_exists?
178
-
179
- # if don't reopen temp file, can't lock...
180
- reopen_temp_file
181
-
182
- cnt = 0
183
- begin
184
- @@tempf.flock(File::LOCK_EX)
185
-
186
- rescue
187
- cnt += 1
188
- if (cnt <= @try_limit)
189
- sleep(0.5)
190
- create_tempfile if !tempf_exists?
191
- retry
192
- else
193
- SimpleRotate::Error.warning("It was not possible to lock (tried 3times) => #{@@tempf_name}")
194
- return false
195
- end
196
- end
197
- end
198
-
199
- # unlock the temp file
200
- def unlock
201
- return nil if !tempf_exists?
202
-
203
- begin
204
- @@tempf.flock(File::LOCK_UN)
205
- rescue
206
- SimpleRotate::Error.warning("It was not possible to unlock => #{@@tempf_name}")
207
- end
208
- end
209
- end
210
-
211
- #
212
- # The classes for process-safe
213
- #
214
- class ProcessSync
215
- include ProcessSyncMixin
216
-
217
- ProcessSyncMixin.instance_methods.each do |method_name|
218
- method = instance_method(method_name)
219
- define_method(method_name) do |*args|
220
- ###################
221
- # common execution
222
- ###################
223
- # Processing to be performed at the beginning of the method
224
- return nil if !@enable
225
- ###################
226
- method.bind(self).call(*args)
227
- end
228
- end
229
-
230
- def initialize(sr)
231
- @sr = sr
232
- @enable = sr.instance_variable_get(:@psafe_mode)
233
- @file_name = sr.instance_variable_get(:@file_name)
234
-
235
- # #init not called
236
- return self if @file_name == nil
237
-
238
- @logf = sr.instance_variable_get(:@logf)
239
- @try_limit = 3
240
- @@tempf_name = File.dirname(@file_name) + File::SEPARATOR + ".SimpleRotate_tempfile_#{File.basename($0)}"
241
-
242
- create_tempfile if @enable && !@@scheduled_del_lockfile
243
- end
244
-
245
- # Create the temp file for locking
246
- private
247
- def create_tempfile
248
- if File.exist?(@@tempf_name)
249
- open_temp_file
250
- return nil
251
- end
252
-
253
- begin
254
- @@tempf = File.open(@@tempf_name, File::RDWR|File::CREAT|File::EXCL)
255
-
256
- rescue
257
- SimpleRotate::Error.warning("Couldn't create temp file => #{@@tempf_name}")
258
-
259
- ensure
260
- set_delete_tempfile
261
- end
262
- end
263
-
264
- private
265
- def tempf_exists?
266
- return File.exist?(@@tempf_name)
267
- end
268
-
269
- # Delete the lock file at the end of the script
270
- private
271
- def set_delete_tempfile
272
- return true if @@scheduled_del_lockfile
273
-
274
- if File.exists?(@@tempf_name)
275
- # is it empty?
276
- if File.size(@@tempf_name) == 0
277
- delete_at_end
278
- else
279
- # it is not empty
280
- msg = "File is not empty => #{@@tempf_name}#{$-0}"
281
- msg += "Skip to delete temp file!"
282
- SimpleRotate::Error.warning(msg)
283
- end
284
- end
285
- @@scheduled_del_lockfile = true
286
- end
287
-
288
- private
289
- def delete_at_end
290
- at_exit do
291
- begin
292
- File.delete(@@tempf_name)
293
- rescue
294
- #SimpleRotate::Error.warning("Couldn't delete temp file => #{@@tempf_name}")
295
- end
296
- end
297
- end
298
-
299
- private
300
- def reopen_temp_file
301
- close_temp_file
302
- open_temp_file
303
- end
304
-
305
- private
306
- def open_temp_file
307
- if @@tempf.is_a?(IO) && @@tempf.closed? || !@@tempf.is_a?(IO)
308
- begin
309
- @@tempf = File.open(@@tempf_name, File::RDWR|File::CREAT|File::APPEND)
310
- rescue
311
- SimpleRotate::Error.warning("Couldn't open temp file => #{@@tempf_name}")
312
- end
313
- end
314
- end
315
-
316
- private
317
- def close_temp_file
318
- if @@tempf.is_a?(IO) && !@@tempf.closed?
319
- begin
320
- @@tempf.close
321
- rescue
322
- SimpleRotate::Error.warning("Couldn't close temp file => #{@@tempf_name}")
323
- end
324
- end
325
- end
326
- end
327
-
328
- #--------------------
329
- # access definitions
330
- #--------------------
331
- attr_accessor :threshold,
332
- :date_format,
333
- :logging_format,
334
- :rename_format,
335
- :allow_overwrite,
336
- :sleep_time
337
-
338
- attr_reader :limit
339
-
340
- #----------------
341
- # public methods
342
- #----------------
343
- #
344
- # return method missing error
345
- #
346
- def method_missing(name, *argv)
347
- SimpleRotate::Error.missing(name)
348
- end
349
-
350
- #
351
- # @param string|symbol $file_name
352
- # @param string|int $limit
353
- # @param int $rotation
354
- # @return self
355
- #
356
- def init(file_name=File.absolute_path($0+".log"), limit='1M', rotation=0)
357
- @file_name = file_name
358
- @limit = limit
359
- @rotation = rotation
360
-
361
- # load defaults
362
- include_defaults
363
-
364
- # validation
365
- valid_file_name
366
- valid_int("rotation", @rotation)
367
-
368
- # stdout only
369
- return self if @only_stdout
370
-
371
- if rotate_by_term?
372
- # term rotation
373
- set_days_cnt_of_term
374
- @limit_term = @limit
375
- @rotate_by_term = true
376
-
377
- else
378
- # file_size rotation
379
- @limit_size = trim_byte(@limit)
380
- if @limit_size <= 0
381
- SimpleRotate::Error.argv("limit", @limit)
382
- end
383
- @rotate_by_term = false
384
- end
385
-
386
- # for process safe
387
- @psync = ProcessSync.new(self)
388
-
389
- # open or generate the log file
390
- synchronize do
391
- @psync.lock
392
-
393
- prepare_logf
394
-
395
- @psync.unlock
396
- end
397
-
398
- # if block given, colse IO
399
- if defined? yield
400
- yield self
401
- e
402
- end
403
-
404
- return self
405
- end
406
-
407
- #
408
- # log message out to STDOUT when use SimpleRotate#w method
409
- #
410
- def with_stdout
411
- @with_stdout = true
412
- end
413
-
414
- #
415
- # enable compress
416
- #
417
- def compress
418
- @compress = true
419
- use_zlib
420
- end
421
-
422
- #
423
- # define the compression level
424
- # this method load 'zlib'
425
- # this method enable compress flag
426
- # @param int level - 0-9
427
- # default is 6
428
- #
429
- def compress_level(level)
430
- @compress_level = level
431
- valid_int("compress_level", @compress_level)
432
- compress
433
-
434
- return level
435
- end
436
-
437
- #
438
- # @param string $log message write to log file
439
- # @return string
440
- #
441
- def w(log)
442
- if @file_name == nil
443
- msg = "file_name is Nil Class! Please call #init method"
444
- SimpleRotate::Error.throw_error(msg)
445
- end
446
-
447
- # don't out log message if Doesn't reach threshold
448
- return nil if (!over_threshold?)
449
-
450
- content = get_trimmed_log(log)
451
-
452
- # return and end func, if only_stdout enable
453
- if @only_stdout
454
- puts content
455
- return log
456
- end
457
-
458
- # write message to file
459
- synchronize do
460
- @psync.lock
461
-
462
- sync_inode
463
- @logf.puts(content)
464
- @logf.flush if @enable_wflush
465
- @logf.fsync if @enable_wflush
466
-
467
- @psync.unlock
468
- end
469
-
470
- # dump log message STDOUT, if with_stdout enable
471
- puts content if @with_stdout
472
-
473
- # rotate if necessary
474
- rotate_if if !@no_wcheck
475
-
476
- return log
477
- end
478
-
479
- #
480
- # disable call File#flush after #w method
481
- #
482
- def enable_wflush
483
- @enable_wflush = true
484
- end
485
-
486
- #
487
- # enable call File#flush after #w method
488
- #
489
- def disable_wflush
490
- @enable_wflush = false
491
- end
492
-
493
- #
494
- # close file
495
- #
496
- def e
497
- return nil if logf_not_usable
498
-
499
- synchronize do
500
- @psync.lock
501
-
502
- @logf.close
503
-
504
- @psync.unlock
505
- end
506
- end
507
-
508
- #
509
- # file reopen
510
- #
511
- def reopen
512
- return nil if logf_not_usable
513
-
514
- if !file_closed?
515
- SimpleRotate::Error.warning("File is already open!")
516
- return nil
517
- end
518
-
519
- openadd
520
- return @logf
521
- end
522
-
523
- #
524
- # force rotation
525
- #
526
- def flush
527
- return nil if logf_not_usable
528
- return nil if @rotate_by_term
529
- rotation(:FLUSH)
530
- end
531
-
532
- #
533
- # don't check can to rotate at #w method
534
- #
535
- def no_wcheck
536
- @no_wcheck = true
537
- end
538
-
539
- #
540
- # is log file open?
541
- # @return nil|bool
542
- #
543
- def file_closed?
544
- return nil if logf_not_usable
545
- return @logf.closed?
546
- end
547
-
548
- #
549
- # skip warning message
550
- #
551
- def silence
552
- SimpleRotate::Error.silence
553
- end
554
-
555
- #
556
- # set log level FATAL
557
- # @return self
558
- #
559
- def fatal
560
- @log_level = 5
561
- return self
562
- end
563
-
564
- #
565
- # set log level ERROR
566
- # @return self
567
- #
568
- def error
569
- @log_level = 4
570
- return self
571
- end
572
-
573
- #
574
- # set log level WORN
575
- # @return self
576
- #
577
- def warn
578
- @log_level = 3
579
- return self
580
- end
581
-
582
- #
583
- # set log level INFO
584
- # @return self
585
- #
586
- def info
587
- @log_level = 2
588
- return self
589
- end
590
-
591
- #
592
- # set log level DEBUG
593
- # @return self
594
- #
595
- def debug
596
- @log_level = 1
597
- return self
598
- end
599
-
600
- #
601
- # try to be a safe process
602
- #
603
- def psafe_mode(sleep_time=0.1)
604
- @psafe_mode = true
605
- @enable_wflush = true
606
- @sleep_time = sleep_time
607
-
608
- @psync = ProcessSync.new(self)
609
- end
610
-
611
- #
612
- # Reopen file necessary
613
- # @return bool|nil
614
- #
615
- def sync_inode
616
- return nil if logf_not_usable
617
-
618
- cnt = 0
619
- begin
620
- # check i-node number
621
- open_inode = @logf.stat.ino
622
- logf_inode = File.stat(@file_name).ino
623
- raise if open_inode != logf_inode
624
- rescue
625
- cnt += 1
626
- sleep(0.1)
627
- e
628
- openadd
629
-
630
- if cnt <= @sync_inode_limit
631
- retry
632
- else
633
- SimpleRotate::Error.warning(%{inode number didn't not match, tried #{cnt} times!})
634
- return false
635
- end
636
- end
637
-
638
- return true
639
- end
640
-
641
- #
642
- # Disable #sync_inode
643
- #
644
- def no_sync_inode
645
- @no_sync_inode = true
646
- end
647
-
648
- #----------------
649
- # private methods
650
- #----------------
651
- #
652
- # log file is not IO class or stdout only
653
- # @return bool
654
- #
655
- private
656
- def logf_not_usable
657
- !@logf.is_a?(IO) || @only_stdout
658
- end
659
-
660
- #
661
- # load zlib lib
662
- #
663
- private
664
- def use_zlib
665
- begin
666
- require "zlib"
667
- @compress_level = Zlib::DEFAULT_COMPRESSION if @compress_level == nil
668
-
669
- rescue LoadError
670
- SimpleRotate::Error.load("zlib")
671
- end
672
- end
673
-
674
- #
675
- # open or generate the log file
676
- #
677
- private
678
- def prepare_logf
679
- if File.exist?(@file_name)
680
- # open the exists file, add mode
681
- openadd
682
-
683
- # rotate it if necessary
684
- rotate_if
685
-
686
- else
687
- gen_new_logf
688
- end
689
- end
690
-
691
- #
692
- # generate new log file
693
- #
694
- private
695
- def gen_new_logf
696
- begin
697
- @logf = File.open(@file_name, File::RDWR|File::CREAT|File::TRUNC)
698
- gtime = Time.new.to_i
699
- @logf.puts("created@#{gtime}@Please don't delete this line")
700
- @logf.close
701
-
702
- rescue
703
- SimpleRotate::Error.open(@file_name)
704
- end
705
-
706
- openadd
707
- end
708
-
709
- #
710
- # if file or directory exist, call error
711
- #
712
- private
713
- def exist_error(file)
714
- SimpleRotate::Error.exist(file, "File") if File.exist?(file)
715
- SimpleRotate::Error.exist(file, "Directory") if Dir.exist?(file)
716
-
717
- return true
718
- end
719
-
720
- #
721
- # define default instance vars
722
- #
723
- private
724
- def include_defaults
725
- que = []
726
- que << [%{@threshold}, %{LOG_LEVEL_2}]
727
- que << [%{@log_level}, %{2}]
728
- que << [%{@logging_format}, %{"[$DATE] - $LEVEL : $LOG"}]
729
- que << [%{@date_format}, %{"%Y/%m/%d %H:%M:%S"}]
730
- que << [%{@term_format}, %{"%Y%m%d"}]
731
- que << [%{@rename_format}, %{"."}]
732
- que << [%{@with_stdout}, %{false}]
733
- que << [%{@only_stdout}, %{false}]
734
- que << [%{@no_wcheck}, %{false}]
735
- que << [%{@sync_inode_limit}, %{3}]
736
- que << [%{@no_sync_inode}, %{false}]
737
- que << [%{@enable_wflush}, %{false}]
738
- que << [%{@compress}, %{false}]
739
- que << [%{@psafe_mode}, %{false}]
740
- que << [%{@sleep_time}, %{0}]
741
-
742
- que.each do |q|
743
- if eval(%{#{q[0]} == nil})
744
- eval(%{#{q[0]} = #{q[1]}})
745
- end
746
- end
747
- end
748
-
749
- #
750
- # Whether to rotate by file age?
751
- # @return bool
752
- #
753
- private
754
- def rotate_by_term?
755
- if @limit.is_a?(Integer)
756
- return false
757
-
758
- elsif @limit.is_a?(String)
759
- return @limit.to_i == 0
760
-
761
- else
762
- SimpleRotate::Error.argv("limit", @limit)
763
- end
764
- end
765
-
766
- #
767
- # Open the log file, add mode
768
- #
769
- private
770
- def openadd
771
- @logf = File.open(@file_name, File::RDWR|File::CREAT|File::APPEND)
772
-
773
- # refresh object
774
- @psync = ProcessSync.new(self)
775
- end
776
-
777
- #
778
- # get cretated time of the log file
779
- # @return Time
780
- #
781
- private
782
- def get_logf_generate_time
783
- pos = @logf.pos
784
- begin
785
- @logf.rewind
786
- stamp = @logf.readline.split("@")
787
- @logf.seek(pos)
788
- gtime = Time.at(stamp[1].to_i)
789
-
790
- rescue StandardError, SyntaxError
791
- msg = "Can't get file creation time!"
792
- gtime = Time.now
793
- SimpleRotate::Error.warning(msg)
794
- end
795
-
796
- return gtime
797
- end
798
-
799
- #
800
- # @return int
801
- #
802
- private
803
- def set_days_cnt_of_term
804
- begin
805
- @dayc = eval("TERM_#{@limit}")
806
- rescue NameError
807
- SimpleRotate::Error.argv("limit", @limit)
808
- end
809
- end
810
-
811
- #
812
- # log file size over 'limit_size'?
813
- # @return bool|nil
814
- #
815
- private
816
- def over_size?
817
- return nil if logf_not_usable
818
-
819
- begin
820
- rst = File.size(@file_name) > @limit_size
821
- rescue
822
- rst = false
823
- end
824
-
825
- return rst
826
- end
827
-
828
- private
829
- def safe_over_size?
830
- rst = nil
831
- synchronize do
832
- @psync.lock
833
- rst = over_size?
834
- @psync.unlock
835
- end
836
-
837
- return rst
838
- end
839
-
840
- #
841
- # logfile's elapsed days is over limit?
842
- # @return bool
843
- #
844
- private
845
- def over_term?
846
- return nil if logf_not_usable
847
-
848
- begin
849
- now_time = Time.now
850
- gen_time = get_logf_generate_time
851
- estimated_time = gen_time + (60 * 60 * 24 * @dayc)
852
- rst = estimated_time <= now_time
853
- rescue
854
- rst = false
855
- end
856
-
857
- return rst
858
- end
859
-
860
- private
861
- def safe_over_term?
862
- rst = nil
863
- synchronize do
864
- @psync.lock
865
- rst = over_term?
866
- @psync.unlock
867
- end
868
-
869
- return rst
870
- end
871
-
872
- #
873
- # Format the text for logging
874
- # the following characters are recognized
875
- # $DATE => date
876
- # $LEVEL => log's severity
877
- # $LOG => your log message
878
- # $PID => process ID
879
- # $FILE => execute file name
880
- #
881
- # @param string $log
882
- # @return string
883
- #
884
- private
885
- def get_trimmed_log(log)
886
- log = log.to_s
887
- date = Time.now.strftime(@date_format)
888
- level = eval("LOG_LEVEL_#{@log_level}")
889
- return @logging_format.gsub("$DATE", date)
890
- .gsub("$LEVEL", level)
891
- .gsub("$LOG", log)
892
- .gsub("$PID", $$.to_s)
893
- .gsub("$FILE-FUL", File.absolute_path($0))
894
- .gsub("$FILE", File.basename($0))
895
- end
896
-
897
- #
898
- # Whether that is the output of the log level that exceeds the threshold
899
- # @return boolean
900
- #
901
- private
902
- def over_threshold?
903
- begin
904
- return (@log_level >= eval("LEVEL_ID_#{@threshold}"))
905
- rescue NameError
906
- SimpleRotate::Error.argv("threshold", @threshold)
907
- end
908
- end
909
-
910
- #
911
- # need rotate?
912
- # @return bool
913
- #
914
- private
915
- def reached_limit?(mode=:NO_LOCK)
916
- # file age rotation
917
- if @rotate_by_term
918
- is_over_term = nil
919
- if mode == :NO_LOCK
920
- is_over_term = over_term?
921
- elsif mode == :LOCK
922
- is_over_term = safe_over_term?
923
- end
924
-
925
- return is_over_term
926
- end
927
-
928
- # file size rotation
929
- is_over_size = nil
930
- if mode == :NO_LOCK
931
- is_over_size = over_size?
932
- elsif mode == :LOCK
933
- is_over_size = safe_over_size?
934
- end
935
-
936
- return is_over_size
937
- end
938
-
939
- #
940
- # Rotates as necessary
941
- # @return bool
942
- #
943
- private
944
- def rotate_if
945
- if reached_limit?(:LOCK)
946
- rotation
947
- return true
948
-
949
- else
950
- # no need to rotate
951
- return false
952
- end
953
- end
954
-
955
- #
956
- # prepare & call #do_rotation
957
- #
958
- private
959
- def rotation(mode=:NO_SPEC)
960
- synchronize do
961
- # if rotationing now by another process, return
962
- if @psync.locked? #=> if not process safe mode, will be return nil
963
- return false
964
- end
965
-
966
- # lock another process if enable
967
- @psync.lock
968
-
969
- do_rotate(mode)
970
-
971
- # unlock another process if enable
972
- @psync.unlock
973
- end
974
- end
975
-
976
- #
977
- # Rotate the log file now, and open a new one
978
- #
979
- private
980
- def do_rotate(mode)
981
- return nil if logf_not_usable
982
-
983
- # check already executed rotation?
984
- if mode != :FLUSH && !reached_limit?
985
- return false
986
- end
987
-
988
- # file age rotation
989
- if @rotate_by_term
990
- rtn = do_term_rotate
991
- return rtn
992
- end
993
-
994
- # file size rotation
995
- cnt = 1
996
- rotate_name = "#{@file_name}#{@rename_format}#{cnt}"
997
- rotate_name += ".gz" if @compress
998
-
999
- if File.exist?(rotate_name)
1000
- while File.exist?(rotate_name)
1001
- cnt += 1
1002
- rotate_name = "#{@file_name}#{@rename_format}#{cnt}"
1003
- rotate_name += ".gz" if @compress
1004
- end
1005
-
1006
- rename_wait_que = Array.new
1007
- for nc in 1...cnt
1008
- break if @rotation == 1
1009
- if (@compress)
1010
- rename_wait_que << "File.rename('#{@file_name}#{@rename_format}#{nc}.gz', '#{@file_name}#{@rename_format}#{nc+1}.gz')"
1011
- else
1012
- rename_wait_que << "File.rename('#{@file_name}#{@rename_format}#{nc}', '#{@file_name}#{@rename_format}#{nc+1}')"
1013
- end
1014
-
1015
- if @rotation
1016
- next if @rotation == 0
1017
- break if @rotation <= nc+1
1018
- end
1019
- end
1020
-
1021
- rename_wait_que.reverse!
1022
-
1023
- begin
1024
- rename_wait_que.each do |do_rename|
1025
- eval(do_rename)
1026
- end
1027
- rescue
1028
- SimpleRotate::Error.warning(SimpleRotate::Error::ROTATION_FAILED)
1029
- return false
1030
- end
1031
- end
1032
-
1033
- most_recent_name = "#{@file_name}#{@rename_format}1"
1034
- post_execute_rotate(most_recent_name)
1035
- end
1036
-
1037
- #
1038
- # Rotate the log file now, and open a new one
1039
- # for rotate by term
1040
- #
1041
- private
1042
- def do_term_rotate
1043
- date = Time.now.strftime(@term_format)
1044
- rotate_name = "#{@file_name}#{@rename_format}#{date}"
1045
-
1046
- # Don't rotation If a file with the same name already exists
1047
- return false if File.exists?(rotate_name)
1048
- return false if File.exists?("#{rotate_name}.gz")
1049
-
1050
- post_execute_rotate(rotate_name)
1051
- end
1052
-
1053
- #
1054
- # rename log_file & generate new one
1055
- #
1056
- private
1057
- def post_execute_rotate(after_name)
1058
- begin
1059
- @logf.close
1060
- File.rename(@file_name, after_name)
1061
- do_compress(after_name) if @compress
1062
- prepare_logf
1063
-
1064
- # sleep after rotation
1065
- sleep(@sleep_time) if @sleep_time > 0
1066
-
1067
- rescue
1068
- SimpleRotate::Error.warning(SimpleRotate::Error::ROTATION_FAILED)
1069
- reopen if file_closed?
1070
- end
1071
- end
1072
-
1073
- #
1074
- # compress rotated file
1075
- #
1076
- private
1077
- def do_compress(file)
1078
- contents = nil
1079
- File.open(file, File::RDONLY) do |f|
1080
- contents = f.read
1081
- end
1082
-
1083
- newf = "#{file}.gz"
1084
-
1085
- io = File.open(newf, File::WRONLY|File::CREAT|File::TRUNC)
1086
- Zlib::GzipWriter.wrap(io, @compress_level) do |writer|
1087
- writer.mtime = File.mtime(file).to_i
1088
- writer.orig_name = file
1089
- writer.write(contents)
1090
- end
1091
-
1092
- File.delete(file)
1093
- end
1094
-
1095
- #
1096
- # convert 'limit_size' to integer
1097
- # @param string|int $limit_size
1098
- # @return int
1099
- #
1100
- private
1101
- def trim_byte(limit)
1102
- return limit if limit.is_a?(Integer)
1103
-
1104
- kiro = "000"
1105
- mega = kiro + "000"
1106
- giga = mega + "000"
1107
- tera = giga + "000"
1108
- limit_size = limit
1109
-
1110
- if /K$/ =~ limit_size
1111
- limit_size = limit_size.sub(/K$/, "") + kiro
1112
- elsif /M$/ =~ limit_size
1113
- limit_size = limit_size.sub(/M$/, "") + mega
1114
- elsif /G$/ =~ limit_size
1115
- limit_size = limit_size.sub(/G$/, "") + giga
1116
- elsif /T$/ =~ limit_size
1117
- limit_size = limit_size.sub(/T$/, "") + tera
1118
- end
1119
-
1120
- return limit_size.to_i
1121
- end
1122
-
1123
- #--------------------
1124
- # method alias
1125
- #--------------------
1126
- alias_method :<<, :w
1127
- end
3
+ # Simple and safety logger
4
+ # @autor: Kazuya Hotta
5
+ #
6
+ require_relative "simple_rotate/core.rb"