root/trunk/bevutils/Log4D.d

Revision 20, 5.9 kB (checked in by teales, 1 year ago)

Bevutils files initial check-in.

Line 
1 /***************************************************************
2 Copyright (c) Steve Teale 2007
3 This program is free software; you can use it for any purpose
4 subject to the following conditions.
5
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR ANY PARTICULAR PURPOSE.
9 ****************************************************************/
10 module bevutils.log4d;
11
12 import std.stdio;
13 import std.file;
14 import std.date;
15 import std.stream;
16 import std.regexp;
17 import std.string;
18
19 /**
20  * General purpose logging class with file count and size limits and rollover.
21  *
22  * The name implies no similarity to the workings of log4j
23  */
24 class Log4D
25 {
26 private:
27    const char[] _rex = r"2[0-9]{3}[0-1][0-9][0-3][0-9][0-2][0-9][0-5][0-9][0-5][0-9][0-9]{3}\.log";
28    uint _maxsize;
29    uint _maxfiles;
30    char[] _path;
31    char[] _prefix;
32    char[] _current;
33    int _numlogs;
34    bool _ok, _isopen;
35    int _cycle;
36    File _log;
37
38    private char[] makeLogName()
39    {
40       d_time t = UTCtoLocalTime(getUTCtime());
41       Date d;
42       d.fromTicks(t);
43       char[] ds = std.string.format("%d%02d%02d%02d%02d%02d%03d", d.year, d.month, d.day, d.hour, d.minute, d.second, d.ms);
44       return std.string.format("%s\\%s%s.log", _path, _prefix, ds);
45    }
46
47    private void findCurrent()
48    {
49       char[][] list = listthisdir(_path, RegExp(_prefix ~ _rex));
50       _numlogs = list.length;
51       if (_numlogs)
52       {
53          list = list.sort;
54          _current = list[_numlogs-1];
55       }
56       else
57       {
58          _current = makeLogName();
59          _numlogs = 1;
60       }
61    }
62
63
64    private bool rollOver()
65    {
66       if (_isopen)
67       {
68          _log.close();
69          _isopen = false;
70       }
71       ulong sz = getSize(_current);
72       if (sz < _maxsize)
73       {
74          _log = new File(_current, std.stream.FileMode.Append);
75          _isopen = true;
76          return false;
77       }
78       char[] newname = makeLogName();
79       if (newname == _current)
80       {
81          // We've filled a log file in less than a millisecond - increase _maxsize
82          // but in this case, just lie and continue to grow the existing file
83          return true;
84       }
85       _current = newname;
86       // Create empty file
87       std.file.write(_current, cast(void[])"");
88       _numlogs++;
89
90       if (_numlogs > _maxfiles)
91       {
92          int n = _numlogs - _maxfiles;
93          char[][] list = listthisdir(_path, RegExp(_prefix ~ _rex));
94          if (list.length)
95          {
96             list = list.sort;
97             for (int i = 0; i < n; i++)
98             {
99                std.file.remove(list[i]);
100             }
101             _numlogs = _maxfiles;
102          }
103          else
104             _numlogs = 0;
105       }
106
107       return true;
108    }
109
110 public:
111    /**
112     * At the moment there is only one logging style, but please feel free to roll your own.
113     */
114    enum Log4DStyle
115    {
116       STD
117    }
118
119    /**
120     * Single constructor
121     *
122     * Log files are named with a prefix to indicate their host application, and a timestamp to
123     * the millisecond.
124     *
125     * Params:
126     *    path = Path to the directory where log files are to be kept
127     *    prefix = Distinguishing prefix for the log files - usually an abbreviation of the host application name.
128     *    style = One of possibly several styles mentioned in enum Log4DStyle - only one now.
129     *    maxfiles = Maximum number of log files to retain at any time.
130     *    maxsize = Size at which to rollover and create a new log file.
131     */
132    this(char[] path, char[] prefix, Log4DStyle style = Log4DStyle.STD, int maxfiles = 0, int maxsize = 0)
133    {
134       _ok = false;
135       _isopen = false;
136       _cycle = 0;
137       _log = null;
138       _maxsize = (maxsize == 0)? 0x400000: maxsize;
139       if (_maxsize < 0x100000)
140          _maxsize = 0x100000;       // Get a bigger hard drive ;=)
141       _maxfiles = (maxfiles == 0)? 5: maxfiles;
142       int l = path.length;
143       if (path[l-1] == '\\')
144       path.length = l-1;
145       _path = path;
146       _prefix = prefix;
147       _current = "";
148       _numlogs = 0;
149       try
150       {
151          findCurrent();
152          _log = new File(_current, std.stream.FileMode.Append);
153          _isopen = true;
154          _ok = true;
155       }
156       catch (Exception) {}
157    }
158
159    ~this() { _log.close(); }
160
161    /**
162     * Sentinel to check that the logger was created OK.
163     */
164    public bool OK() { return _ok; }
165
166
167    /**
168     * The method to log messages.
169     *
170     * Override this to create you own message formats
171     *
172     * This version creates log entries like:<br>
173     * "[YYYY-MM-DD HH:MM:SS:mmm] INFO: The message"
174     *
175     * Params:
176     *    msgType = A string to label the message after the timestamp - e.g. INFO
177     *    msg = The text to be logged
178     */
179    public synchronized void logMessage(char[] msgType, char[] msg)
180    {
181       // Check occasionally to see if the log file is over its stipulated size,
182       // and start a new one if it is.
183       if (_cycle > 20)
184       {
185          if (rollOver())
186          {
187             _log = new File(_current, std.stream.FileMode.Append);
188             _isopen = true;
189             _cycle = 0;
190          }
191       }
192       else
193          _cycle++;
194
195       d_time t = UTCtoLocalTime(getUTCtime());
196       Date d;
197       d.fromTicks(t);
198       char[] ds = std.string.format("[%d-%02d-%02d %02d:%02d:%02d:%03d] %s: %s",
199                            d.year, d.month, d.day, d.hour, d.minute, d.second, d.ms, msgType, msg);
200          
201       _log.writeLine(ds);
202    }
203 }
204
205 /+
206 void main(char[][] args)
207 {
208    Log4D log = new Log4D(r"d:\aaa", "XYZ");
209    for (int i = 0; i < 2000000; i++)
210       log.logMessage("INFO", "A somewhat long and pointless message simply intended to fill up reams of log file and otherwise to achieve nothing.");
211 }
212 +/
Note: See TracBrowser for help on using the browser.