simple_rotate 0.0.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 57afd4b6d133d914743e6d548507323c5f6f9926
4
+ data.tar.gz: a5a6cf55f8e7894d9c7c090a7f0b429161aad2c9
5
+ SHA512:
6
+ metadata.gz: 220d55fbab5182dcc7a767113c35b948c9d10c58f23b18e1fe66ff7b5570ebb550964aea5ed5df6f603585dfe2939049db366f51b59d9c4940c9f242badc3fc6
7
+ data.tar.gz: f66d8796b8f5cb125541041a621363fdaba0431c81c47e666b43c65f0ed5274dea1a1aa6f5077a37a887242e8d60e63fc466d2e0ed155503847bcf09b5846ad8
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Kazuya Hotta
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ Thank you for installing! (^-^)
2
+ See also http://khotta.github.io/simple_rotate
@@ -1,8 +1,1127 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ # SimpleRotate - simple logger for ruby
2
+ # @autor: Kazuya Hotta (nyanko)
3
+ #
4
+ require "singleton"
5
+ require "monitor"
3
6
 
4
- module SimpleRotateVersionInfo
5
- VERSION = '0.0.3'
6
- end
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
7
522
 
8
- require 'simple_rotate/simple_rotate'
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