File: Log.rb

package info (click to toggle)
tj3 3.8.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,048 kB
  • sloc: ruby: 36,481; javascript: 1,113; sh: 19; makefile: 17
file content (174 lines) | stat: -rw-r--r-- 5,475 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = Log.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
#               by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#

require 'singleton'
require 'monitor'
require 'term/ansicolor'

class TaskJuggler

  # The Log class implements a filter for segmented execution traces. The
  # trace messages are filtered based on their segment name and the nesting
  # level of the segments. The class is a Singleton, so there is only one
  # instance in the program.
  class Log < Monitor

    include Singleton

    @@level = 0
    @@stack = []
    @@segments = []
    @@silent = true
    @@progress = 0
    @@progressMeter = ''

    # Set the maximum nesting level that should be shown. Segments with a
    # nesting level greater than _l_ will be silently dropped.
    def Log.level=(l)
      @@level = l
    end

    # The trace output can be limited to a list of segments. Messages not in
    # these segments will be ignored. Messages from segments that are nested
    # into the shown segments will be shown for the next @@level nested
    # segments.
    def Log.segments=(s)
      @@segments = s
    end

    # if +s+ is true, progress information will not be shown.
    def Log.silent=(s)
      @@silent = s
    end

    # Return the @@silent value.
    def Log.silent
      @@silent
    end

    # This function is used to open a new segment. +segment+ is the name of
    # the segment and +message+ is a description of it.
    def Log.enter(segment, message)
      return if @@level == 0

      @@stack << segment
      Log.msg { ">> [#{segment}] #{message}" }
    end

    # This function is used to close an open segment. To make this mechanism a
    # bit more robust, it will search the stack of open segments for a segment
    # with that name and will close all nested segments as well.
    def Log.exit(segment, message = nil)
      return if @@level == 0

      Log.msg { "<< [#{segment}] #{message}" } if message
      if @@stack.include?(segment)
        loop do
          m = @@stack.pop
          break if m == segment
        end
      end
    end

    # Use this function to show a log message within the currently active
    # segment. The message is the result of the passed block. The block will
    # only be evaluated if the message will actually be shown.
    def Log.msg(&block)
      return if @@level == 0

      offset = 0
      unless @@segments.empty?
        showMessage = false
        @@stack.each do |segment|
          # If a segment list is used to filter the output, we look for the
          # first listed segments on the stack. This and all nested segments
          # will be shown.
          if @@segments.include?(segment)
            offset = @@stack.index(segment)
            showMessage = true
            break
          end
        end
        return unless showMessage
      end
      if @@stack.length - offset < @@level
        $stderr.puts ' ' * (@@stack.length - offset) + yield(block)
      end
    end

    # Print out a status message unless we are in silent mode.
    def Log.status(message)
      return if @@silent

      $stdout.puts message
    end

    # The progress meter can be a textual progress bar or some animated
    # character sequence that informs the user about ongoing activities. Call
    # this function to start the progress meter display or to change the info
    # +text+. The the meter is active the text cursor is always returned to
    # the start of the same line. Consequent output will overwrite the last
    # meter text.
    def Log.startProgressMeter(text)
      return if @@silent

      maxlen = 60
      text = text.ljust(maxlen)
      text = text[0..maxlen - 1] if text.length_utf8 > maxlen
      @@progressMeter = text
      $stdout.print("#{@@progressMeter} ...\r")
    end

    # This sets the progress meter status to "done" and puts the cursor into
    # the next line again.
    def Log.stopProgressMeter
      return if @@silent

      $stdout.print("#{@@progressMeter} [      " +
                    Term::ANSIColor.green("Done") + "      ]\n")
    end

    # This function may only be called when Log#startProgressMeter has been
    # called before. It updates the progress indicator to the next symbol to
    # visualize ongoing activity.
    def Log.activity
      return if @@silent

      indicator = %w( - \\ | / )
      @@progress = (@@progress.to_i + 1) % indicator.length
      $stdout.print("#{@@progressMeter} [#{indicator[@@progress]}]\r")
    end

    # This function may only be called when Log#startProgressMeter has been
    # called before. It updates the progress bar to the given +percent+
    # completion value. The value should be between 0.0 and 1.0.
    def Log.progress(percent)
      return if @@silent

      percent = 0.0 if percent < 0.0
      percent = 1.0 if percent > 1.0
      @@progress = percent

      length = 16
      full = (length * percent).to_i
      bar = '=' * full + ' ' * (length - full)
      label = (percent * 100.0).to_i.to_s + '%'
      bar[length / 2 - label.length / 2, label.length] = label
      $stdout.print("#{@@progressMeter} [" +
                    Term::ANSIColor.green("#{bar}") + "]\r")
    end

  end

end