001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.log;
030:
031: import java.util.ArrayList;
032:
033: import com.caucho.loader.Environment;
034: import com.caucho.server.util.CauchoSystem;
035: import com.caucho.util.Alarm;
036: import com.caucho.util.QDate;
037: import com.caucho.vfs.Path;
038: import com.caucho.vfs.StreamImpl;
039: import com.caucho.vfs.WriteStream;
040:
041: import java.io.IOException;
042:
043: /**
044: * Automatically-rotating streams. Normally, clients will call
045: * getStream instead of using the StreamImpl interface.
046: */
047: public class TimestampFilter extends StreamImpl {
048:
049: static final String[] DAY_NAMES = { "Sun", "Mon", "Tue", "Wed",
050: "Thu", "Fri", "Sat" };
051: static final String[] MONTH_NAMES = { "Jan", "Feb", "Mar", "Apr",
052: "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
053:
054: private static final String[] SHORT_WEEKDAY = { "Sun", "Mon",
055: "Tue", "Wed", "Thu", "Fri", "Sat" };
056: private static final String[] LONG_WEEKDAY = { "Sunday", "Monday",
057: "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
058: private static final String[] SHORT_MONTH = { "Jan", "Feb", "Mar",
059: "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
060: "Dec", };
061: private static final String[] LONG_MONTH = { "January", "February",
062: "March", "April", "May", "June", "July", "August",
063: "September", "October", "November", "December", };
064:
065: private WriteStream _stream;
066:
067: private String _timestampString;
068: private TimestampBase[] _timestamp;
069:
070: private QDate _calendar = new QDate(true);
071:
072: private boolean _isLineBegin = true;
073:
074: /**
075: * Create listener.
076: *
077: * @param path underlying log path
078: */
079: public TimestampFilter() {
080: }
081:
082: /**
083: * Create listener.
084: *
085: * @param path underlying log path
086: */
087: public TimestampFilter(WriteStream out, String timestamp) {
088: _stream = out;
089: setTimestamp(timestamp);
090: }
091:
092: public void setTimestamp(String timestamp) {
093: _timestampString = timestamp;
094:
095: ArrayList<TimestampBase> timestampList = new ArrayList<TimestampBase>();
096: StringBuilder sb = new StringBuilder();
097:
098: for (int i = 0; i < timestamp.length(); i++) {
099: char ch = timestamp.charAt(i);
100:
101: if (ch == '%') {
102: ch = timestamp.charAt(i + 1);
103: switch (ch) {
104: case 'a':
105: case 'A':
106: case 'b':
107: case 'B':
108: case 'c':
109: case 'd':
110: case 'H':
111: case 'I':
112: case 'j':
113: case 'm':
114: case 'M':
115: case 'p':
116: case 'S':
117: case 's':
118: case 'W':
119: case 'w':
120: case 'x':
121: case 'X':
122: case 'y':
123: case 'Y':
124: case 'Z':
125: case 'z':
126: if (sb.length() > 0)
127: timestampList.add(new Text(sb.toString()));
128: sb.setLength(0);
129: timestampList.add(new Code(ch));
130: i++;
131: break;
132:
133: case '{':
134: if (sb.length() > 0)
135: timestampList.add(new Text(sb.toString()));
136: sb.setLength(0);
137: for (i += 2; i < timestamp.length()
138: && timestamp.charAt(i) != '}'; i++) {
139: sb.append((char) timestamp.charAt(i));
140: }
141: String type = sb.toString();
142: sb.setLength(0);
143:
144: if ("thread".equals(type)) {
145: timestampList.add(new ThreadTimestamp());
146: } else if ("env".equals(type)) {
147: timestampList.add(new EnvTimestamp());
148: } else {
149: sb.append("%{" + type + "}");
150: }
151: break;
152:
153: default:
154: sb.append('%');
155: break;
156: }
157: } else
158: sb.append(ch);
159: }
160:
161: if (sb.length() > 0)
162: timestampList.add(new Text(sb.toString()));
163:
164: _timestamp = new TimestampBase[timestampList.size()];
165: timestampList.toArray(_timestamp);
166: }
167:
168: public void setStream(WriteStream stream) {
169: _stream = stream;
170: }
171:
172: public Path getPath() {
173: if (_stream != null)
174: return _stream.getPath();
175: else
176: return super .getPath();
177: }
178:
179: /**
180: * Returns true if the stream can write.
181: */
182: public boolean canWrite() {
183: return _stream != null && _stream.canWrite();
184: }
185:
186: /**
187: * Write data to the stream.
188: */
189: public void write(byte[] buffer, int offset, int length,
190: boolean isEnd) throws IOException {
191: if (_stream == null)
192: return;
193:
194: if (_timestamp == null) {
195: _stream.write(buffer, offset, length);
196: return;
197: }
198:
199: long now;
200:
201: if (CauchoSystem.isTesting())
202: now = Alarm.getCurrentTime();
203: else
204: now = System.currentTimeMillis();
205:
206: for (int i = 0; i < length; i++) {
207: if (_isLineBegin) {
208: // _stream.print(_calendar.formatLocal(now, _timestamp));
209: synchronized (_calendar) {
210: _calendar.setGMTTime(now);
211:
212: int len = _timestamp.length;
213: for (int j = 0; j < len; j++)
214: _timestamp[j].print(_stream, _calendar);
215: }
216:
217: _isLineBegin = false;
218: }
219:
220: int ch = buffer[offset + i];
221: _stream.write(ch);
222:
223: if (ch == '\n' || ch == '\r' && i + 1 < length
224: && buffer[offset + i + 1] != '\n')
225: _isLineBegin = true;
226: }
227: }
228:
229: /**
230: * Flushes the data.
231: */
232: public void flush() throws IOException {
233: if (_stream != null)
234: _stream.flush();
235: }
236:
237: /**
238: * Flushes the data.
239: */
240: public void close() throws IOException {
241: if (_stream != null)
242: _stream.close();
243: }
244:
245: static class TimestampBase {
246: public void print(WriteStream out, QDate cal)
247: throws IOException {
248: }
249: }
250:
251: static class Text extends TimestampBase {
252: private final char[] _text;
253:
254: Text(String text) {
255: _text = text.toCharArray();
256: }
257:
258: public void print(WriteStream out, QDate cal)
259: throws IOException {
260: out.print(_text, 0, _text.length);
261: }
262: }
263:
264: static class Code extends TimestampBase {
265: private final char _code;
266:
267: Code(char code) {
268: _code = code;
269: }
270:
271: public void print(WriteStream out, QDate cal)
272: throws IOException {
273: switch (_code) {
274: case 'a':
275: out.print(SHORT_WEEKDAY[cal.getDayOfWeek() - 1]);
276: break;
277:
278: case 'A':
279: out.print(LONG_WEEKDAY[cal.getDayOfWeek() - 1]);
280: break;
281:
282: case 'b':
283: out.print(SHORT_MONTH[cal.getMonth()]);
284: break;
285:
286: case 'B':
287: out.print(LONG_MONTH[cal.getMonth()]);
288: break;
289:
290: case 'c':
291: out.print(cal.printLocaleDate());
292: break;
293:
294: case 'd':
295: out.print((cal.getDayOfMonth()) / 10);
296: out.print((cal.getDayOfMonth()) % 10);
297: break;
298:
299: case 'H':
300: int hour = (int) (cal.getTimeOfDay() / 3600000) % 24;
301: out.print(hour / 10);
302: out.print(hour % 10);
303: break;
304:
305: case 'I':
306: hour = (int) (cal.getTimeOfDay() / 3600000) % 12;
307: if (hour == 0)
308: hour = 12;
309: out.print(hour / 10);
310: out.print(hour % 10);
311: break;
312:
313: case 'j':
314: out.print((cal.getDayOfYear() + 1) / 100);
315: out.print((cal.getDayOfYear() + 1) / 10 % 10);
316: out.print((cal.getDayOfYear() + 1) % 10);
317: break;
318:
319: case 'm':
320: out.print((cal.getMonth() + 1) / 10);
321: out.print((cal.getMonth() + 1) % 10);
322: break;
323:
324: case 'M':
325: out.print((cal.getTimeOfDay() / 600000) % 6);
326: out.print((cal.getTimeOfDay() / 60000) % 10);
327: break;
328:
329: case 'p':
330: hour = (int) (cal.getTimeOfDay() / 3600000) % 24;
331: if (hour < 12)
332: out.print("am");
333: else
334: out.print("pm");
335: break;
336:
337: case 'S':
338: out.print((cal.getTimeOfDay() / 10000) % 6);
339: out.print((cal.getTimeOfDay() / 1000) % 10);
340: break;
341:
342: case 's':
343: out.print((cal.getTimeOfDay() / 100) % 10);
344: out.print((cal.getTimeOfDay() / 10) % 10);
345: out.print(cal.getTimeOfDay() % 10);
346: break;
347:
348: case 'W':
349: int week = cal.getWeek();
350: out.print((week + 1) / 10);
351: out.print((week + 1) % 10);
352: break;
353:
354: case 'w':
355: out.print(cal.getDayOfWeek() - 1);
356: break;
357:
358: case 'x':
359: out.print(cal.printShortLocaleDate());
360: break;
361:
362: case 'X':
363: out.print(cal.printShortLocaleTime());
364: break;
365:
366: case 'y': {
367: int year = cal.getYear();
368: out.print(year / 10 % 10);
369: out.print(year % 10);
370: break;
371: }
372:
373: case 'Y': {
374: int year = cal.getYear();
375: out.print(year / 1000 % 10);
376: out.print(year / 100 % 10);
377: out.print(year / 10 % 10);
378: out.print(year % 10);
379: break;
380: }
381:
382: case 'Z':
383: if (cal.getZoneName() == null)
384: out.print("GMT");
385: else
386: out.print(cal.getZoneName());
387: break;
388:
389: case 'z':
390: long offset = cal.getZoneOffset();
391:
392: if (offset < 0) {
393: out.print("-");
394: offset = -offset;
395: } else
396: out.print("+");
397:
398: out.print((offset / 36000000) % 10);
399: out.print((offset / 3600000) % 10);
400: out.print((offset / 600000) % 6);
401: out.print((offset / 60000) % 10);
402: break;
403: }
404: }
405: }
406:
407: static class ThreadTimestamp extends TimestampBase {
408: public void print(WriteStream out, QDate cal)
409: throws IOException {
410: out.print(Thread.currentThread().getName());
411: }
412: }
413:
414: static class EnvTimestamp extends TimestampBase {
415: public void print(WriteStream out, QDate cal)
416: throws IOException {
417: out.print(Environment.getEnvironmentName());
418: }
419: }
420: }
|