1 29 30 package com.caucho.vfs; 31 32 import java.util.ArrayList; 33 34 import java.util.logging.Logger; 35 import java.util.logging.Level; 36 37 import java.util.zip.ZipOutputStream; 38 import java.util.zip.GZIPOutputStream; 39 40 import java.io.OutputStream; 41 import java.io.IOException; 42 43 import javax.servlet.ServletContext; 44 import javax.servlet.ServletException; 45 46 import com.caucho.util.Log; 47 import com.caucho.util.L10N; 48 import com.caucho.util.Alarm; 49 import com.caucho.util.QDate; 50 51 import com.caucho.loader.Environment; 52 import com.caucho.loader.CloseListener; 53 54 import com.caucho.config.types.Period; 55 import com.caucho.config.types.Bytes; 56 import com.caucho.config.types.InitProgram; 57 import com.caucho.config.ConfigException; 58 59 60 63 abstract public class AbstractRolloverLog { 64 protected static final L10N L = new L10N(AbstractRolloverLog.class); 65 protected static final Logger log = Log.open(AbstractRolloverLog.class); 66 67 private static final long DAY = 24L * 3600L * 1000L; 69 70 private static final long DEFAULT_ROLLOVER_SIZE = 1024L * 1024L * 1024L; 72 private static final long DEFAULT_ROLLOVER_CHECK_PERIOD = 600L * 1000L; 74 75 private String _rolloverPrefix; 77 78 private String _archiveFormat; 80 81 private long _rolloverPeriod = Period.INFINITE; 83 84 private long _rolloverSize = DEFAULT_ROLLOVER_SIZE; 86 87 private long _rolloverCheckPeriod = DEFAULT_ROLLOVER_CHECK_PERIOD; 89 90 private QDate _calendar = QDate.createLocal(); 91 92 protected Path _path; 93 94 protected String _pathFormat; 95 96 private String _format; 97 98 private long _nextPeriodEnd = -1; 100 private long _nextRolloverCheckTime = -1; 101 102 private WriteStream _os; 103 104 107 public Path getPath() 108 { 109 return _path; 110 } 111 112 115 public void setPath(Path path) 116 { 117 _path = path; 118 } 119 120 123 public String getPathFormat() 124 { 125 return _pathFormat; 126 } 127 128 131 public void setPathFormat(String pathFormat) 132 { 133 _pathFormat = pathFormat; 134 } 135 136 139 public void setArchiveFormat(String format) 140 { 141 _archiveFormat = format; 142 } 143 144 147 public String getArchiveFormat() 148 { 149 return _archiveFormat; 150 } 151 152 157 public void setRolloverPeriod(Period period) 158 { 159 _rolloverPeriod = period.getPeriod(); 160 161 if (_rolloverPeriod > 0) { 162 _rolloverPeriod += 3600000L - 1; 163 _rolloverPeriod -= _rolloverPeriod % 3600000L; 164 } 165 else 166 _rolloverPeriod = Period.INFINITE; 167 } 168 169 174 public long getRolloverPeriod() 175 { 176 return _rolloverPeriod; 177 } 178 179 184 public void setRolloverSize(Bytes bytes) 185 { 186 long size = bytes.getBytes(); 187 188 if (size < 0) 189 _rolloverSize = Bytes.INFINITE; 190 else 191 _rolloverSize = size; 192 } 193 194 199 public long getRolloverSize() 200 { 201 return _rolloverSize; 202 } 203 204 209 public void setRolloverCheckPeriod(long period) 210 { 211 if (period > 1000) 212 _rolloverCheckPeriod = period; 213 else if (period > 0) 214 _rolloverCheckPeriod = 1000; 215 } 216 217 222 public long getRolloverCheckPeriod() 223 { 224 return _rolloverCheckPeriod; 225 } 226 227 230 public void init() 231 throws ServletException, IOException 232 { 233 long now = Alarm.getCurrentTime(); 234 235 _nextRolloverCheckTime = now + _rolloverCheckPeriod; 236 237 Path path = getPath(); 238 239 if (path != null) { 240 path.getParent().mkdirs(); 241 242 _rolloverPrefix = path.getTail(); 243 244 long lastModified = path.getLastModified(); 245 if (lastModified <= 0) 246 lastModified = now; 247 248 _calendar.setGMTTime(lastModified); 249 long zone = _calendar.getZoneOffset(); 250 251 _nextPeriodEnd = Period.periodEnd(lastModified, getRolloverPeriod()); 252 } 253 else 254 _nextPeriodEnd = Period.periodEnd(now, getRolloverPeriod()); 255 256 if (_nextPeriodEnd < _nextRolloverCheckTime && _nextPeriodEnd > 0) 257 _nextRolloverCheckTime = _nextPeriodEnd; 258 259 rolloverLog(now); 260 } 261 262 public boolean isRollover() 263 { 264 long now = Alarm.getCurrentTime(); 265 266 return _nextPeriodEnd <= now || _nextRolloverCheckTime <= now; 267 } 268 269 272 protected void write(byte []buffer, int offset, int length) 273 throws IOException 274 { 275 if (_os == null) 276 openLog(); 277 278 if (_os != null) 279 _os.write(buffer, offset, length); 280 } 281 282 285 protected void flush() 286 throws IOException 287 { 288 if (_os != null) 289 _os.flush(); 290 } 291 292 297 protected void rolloverLog(long now) 298 { 299 _nextRolloverCheckTime = now + _rolloverCheckPeriod; 300 301 Path path = getPath(); 302 303 if (_nextPeriodEnd < now) { 304 closeLogStream(); 305 306 if (getPathFormat() == null) { 307 Path savedPath = getArchivePath(_nextPeriodEnd - 1); 308 movePathToArchive(savedPath); 309 } 310 311 _nextPeriodEnd = Period.periodEnd(now, getRolloverPeriod()); 312 313 if (log.isLoggable(Level.FINE)) 314 log.fine(getPath() + ": next rollover at " + 315 QDate.formatLocal(_nextPeriodEnd)); 316 } 317 else if (path != null && getRolloverSize() <= path.getLength()) { 318 closeLogStream(); 319 320 if (getPathFormat() == null) { 321 Path savedPath = getArchivePath(_nextRolloverCheckTime - 1); 322 movePathToArchive(savedPath); 323 } 324 } 325 326 long nextPeriodEnd = _nextPeriodEnd; 327 if (_nextPeriodEnd < _nextRolloverCheckTime && _nextPeriodEnd > 0) 328 _nextRolloverCheckTime = _nextPeriodEnd; 329 330 if (_os == null) 331 openLog(); 332 } 333 334 337 private void openLog() 338 { 339 closeLogStream(); 340 341 try { 342 WriteStream os = _os; 343 _os = null; 344 345 if (os != null) 346 os.close(); 347 } catch (Throwable e) { 348 log.log(Level.FINER, e.toString(), e); 349 } 350 351 Path path = getPath(); 352 353 if (path == null) { 354 path = getPath(Alarm.getCurrentTime()); 355 } 356 357 try { 358 if (! path.getParent().isDirectory()) 359 path.getParent().mkdirs(); 360 } catch (Throwable e) { 361 log.log(Level.FINER, e.toString(), e); 362 } 363 364 for (int i = 0; i < 3 && _os == null; i++) { 365 try { 366 _os = path.openAppend(); 367 } catch (IOException e) { 368 log.log(Level.INFO, e.toString(), e); 369 } 370 } 371 372 if (_os == null) 373 log.warning(L.l("Can't open access log file '{0}'.", 374 getPath())); 375 } 376 377 380 private void closeLogStream() 381 { 382 try { 383 WriteStream os = _os; 384 _os = null; 385 386 if (os != null) 387 os.close(); 388 } catch (Throwable e) { 389 log.log(Level.FINER, e.toString(), e); 390 } 391 } 392 393 private void movePathToArchive(Path savedPath) 394 { 395 Path path = getPath(); 396 397 String savedName = savedPath.getTail(); 398 399 log.info(L.l("Archiving access log to {0}.", savedName)); 400 401 try { 402 WriteStream os = _os; 403 _os = null; 404 if (os != null) 405 os.close(); 406 } catch (IOException e) { 407 log.log(Level.FINE, e.toString(), e); 408 } 409 410 try { 411 savedPath.getParent().mkdirs(); 412 } catch (Throwable e) { 413 log.log(Level.WARNING, e.toString(), e); 414 } 415 416 try { 417 WriteStream os = savedPath.openWrite(); 418 OutputStream out; 419 420 if (savedName.endsWith(".gz")) 421 out = new GZIPOutputStream(os); 422 else if (savedName.endsWith(".zip")) 423 out = new ZipOutputStream(os); 424 else 425 out = os; 426 427 try { 428 path.writeToStream(out); 429 } finally { 430 try { 431 out.close(); 432 } catch (Throwable e) { 433 log.log(Level.WARNING, e.toString(), e); 434 } 435 436 try { 437 if (out != os) 438 os.close(); 439 } catch (Throwable e) { 440 log.log(Level.WARNING, e.toString(), e); 441 } 442 443 path.remove(); 444 } 445 } catch (Throwable e) { 446 log.log(Level.WARNING, e.toString(), e); 447 } 448 } 449 450 455 protected Path getPath(long time) 456 { 457 String formatString = getPathFormat(); 458 459 if (formatString == null) 460 throw new IllegalStateException(L.l("getPath requires a format path")); 461 462 String pathString = getFormatName(formatString, time); 463 464 return Vfs.lookup().lookup(pathString); 465 } 466 467 472 protected Path getArchivePath(long time) 473 { 474 Path path = getPath(); 475 476 String archiveFormat = getArchiveFormat(); 477 478 String name = getFormatName(archiveFormat, time); 479 480 Path newPath = path.getParent().lookup(name); 481 482 if (newPath.exists()) { 483 if (archiveFormat == null) 484 archiveFormat = _rolloverPrefix + ".%Y%m%d.%H%M"; 485 else if (! archiveFormat.contains("%H")) 486 archiveFormat = archiveFormat + ".%H%M"; 487 else if (! archiveFormat.contains("%M")) 488 archiveFormat = archiveFormat + ".%M"; 489 490 name = getFormatName(archiveFormat, time); 491 492 newPath = path.getParent().lookup(name); 493 } 494 495 return newPath; 496 } 497 498 503 protected String getFormatName(String format, long time) 504 { 505 if (time <= 0) 506 time = Alarm.getCurrentTime(); 507 508 if (format != null) 509 return _calendar.formatLocal(time, format); 510 else if (getRolloverPeriod() % (24 * 3600 * 1000L) == 0) 511 return _rolloverPrefix + "." + _calendar.formatLocal(time, "%Y%m%d"); 512 else 513 return _rolloverPrefix + "." + _calendar.formatLocal(time, "%Y%m%d.%H"); 514 } 515 516 519 public void close() 520 throws IOException 521 { 522 if (_os != null) { 523 WriteStream os = _os; 524 _os = null; 525 526 os.close(); 527 } 528 } 529 } 530 | Popular Tags |