1 /* 2 * Created on 22-Sep-2004 3 * Created by Paul Gardner 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package org.gudy.azureus2.core3.util; 21 22 import java.io.ByteArrayOutputStream; 23 import java.io.File; 24 import java.io.FileOutputStream; 25 import java.io.OutputStreamWriter; 26 import java.io.PrintWriter; 27 import java.text.SimpleDateFormat; 28 import java.util.Calendar; 29 import java.util.Date; 30 import java.util.GregorianCalendar; 31 import java.util.LinkedList; 32 import java.util.TimeZone; 33 34 import org.gudy.azureus2.core3.logging.Logger; 35 36 /** 37 * @author parg 38 * 39 */ 40 public class 41 AEDiagnosticsLogger 42 { 43 private static final int MAX_PENDING = 8*1024; 44 45 private String name; 46 private int max_size; 47 private File debug_dir; 48 private boolean timestamp_enable = true; 49 private boolean force; 50 51 private boolean first_file = true; 52 private boolean first_write = true; 53 private PrintWriter current_writer; 54 55 private LinkedList<StringBuilder> pending; 56 private int pending_size; 57 private boolean direct_writes; 58 59 private boolean close_pws = false; 60 61 private static final String start_date; 62 private static final long timezone_offset; 63 64 static{ 65 long now = System.currentTimeMillis(); 66 67 start_date = new SimpleDateFormat().format( new Date(now)); 68 69 timezone_offset = TimeZone.getDefault().getOffset(now); 70 } 71 72 protected AEDiagnosticsLogger( File _debug_dir, String _name, int _max_size, boolean _direct_writes )73 AEDiagnosticsLogger( 74 File _debug_dir, 75 String _name, 76 int _max_size, 77 boolean _direct_writes ) 78 { 79 debug_dir = _debug_dir; 80 name = _name; 81 max_size = _max_size; 82 direct_writes = _direct_writes; 83 84 try{ 85 File f1 = getLogFile(); 86 87 first_file = false; 88 89 File f2 = getLogFile(); 90 91 first_file = true; 92 93 // if we were writing to the second file, carry on from there 94 95 if ( f1.exists() && f2.exists()){ 96 97 if ( f1.lastModified() < f2.lastModified()){ 98 99 first_file = false; 100 } 101 } 102 }catch( Throwable ignore ){ 103 104 } 105 } 106 107 public void setForced( boolean _force )108 setForced( 109 boolean _force ) 110 { 111 force = _force; 112 } 113 114 public boolean isForced()115 isForced() 116 { 117 return( force ); 118 } 119 120 protected String getName()121 getName() 122 { 123 return( name ); 124 } 125 126 public void setMaxFileSize( int _max_size )127 setMaxFileSize( 128 int _max_size ) 129 { 130 max_size = _max_size; 131 } 132 133 public void enableTimeStamp( boolean enable )134 enableTimeStamp( 135 boolean enable ) 136 { 137 timestamp_enable = enable; 138 } 139 140 public void log( Throwable e )141 log( 142 Throwable e ) 143 { 144 try{ 145 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 146 147 PrintWriter pw = new PrintWriter( new OutputStreamWriter( baos )); 148 149 e.printStackTrace( pw ); 150 151 pw.close(); 152 153 log( baos.toString()); 154 155 }catch( Throwable ignore ){ 156 157 } 158 } 159 160 public void logAndOut( String str )161 logAndOut( 162 String str ) 163 { 164 logAndOut( str, false ); 165 } 166 167 public void logAndOut( String str, boolean stderr )168 logAndOut( 169 String str, 170 boolean stderr ) 171 { 172 if ( stderr ){ 173 174 System.err.println( str ); 175 176 // Logger dumps the stderr, but if it's not setup, do it outselves 177 if (Logger.getOldStdErr() == null) { 178 log( str ); 179 } 180 181 }else{ 182 183 System.out.println( str ); 184 log( str ); 185 } 186 187 } 188 189 public void logAndOut( Throwable e )190 logAndOut( 191 Throwable e ) 192 { 193 e.printStackTrace(); 194 195 log( e ); 196 } 197 198 /* 199 public static String 200 getTimestamp() 201 { 202 Calendar now = GregorianCalendar.getInstance(); 203 204 String timeStamp = "[" + format(now.get(Calendar.DAY_OF_MONTH))+format(now.get(Calendar.MONTH)+1) + " " + 205 format(now.get(Calendar.HOUR_OF_DAY))+ ":" + format(now.get(Calendar.MINUTE)) + ":" + format(now.get(Calendar.SECOND)) + "] "; 206 207 return( timeStamp ); 208 } 209 */ 210 211 public static String getTimestamp()212 getTimestamp() 213 { 214 long time = SystemTime.getCurrentTime(); 215 216 time += timezone_offset; // we'll live with this changing... 217 218 time /= 1000; 219 220 int secs = (int)time % 60; 221 int mins = (int)(time / 60) % 60; 222 int hours = (int)(time /3600) % 24; 223 224 char[] chars = new char[11]; 225 226 chars[0] = '['; 227 format( hours, chars, 1 ); 228 chars[3] = ':'; 229 format( mins, chars, 4 ); 230 chars[6] = ':'; 231 format( secs, chars, 7 ); 232 chars[9] = ']'; 233 chars[10] = ' '; 234 235 return( new String( chars )); 236 } 237 238 private static final void format( int num, char[] chars, int pos )239 format( 240 int num, 241 char[] chars, 242 int pos ) 243 { 244 if ( num < 10 ){ 245 chars[pos] = '0'; 246 chars[pos+1] =(char)( '0' + num ); 247 }else{ 248 chars[pos] = (char)('0' + (num/10)); 249 chars[pos+1] = (char)('0' + (num%10)); 250 } 251 } 252 253 public void log( String _str )254 log( 255 String _str ) 256 { 257 if ( !AEDiagnostics.loggers_enabled ){ 258 259 if ( !force ){ 260 261 return; 262 } 263 } 264 265 StringBuilder str = new StringBuilder( _str.length() + 20 ); 266 267 final String timeStamp; 268 269 if ( timestamp_enable ){ 270 271 timeStamp = getTimestamp(); 272 273 }else{ 274 275 timeStamp = null; 276 } 277 278 synchronized( this ){ 279 280 if ( first_write ){ 281 282 first_write = false; 283 284 Calendar now = GregorianCalendar.getInstance(); 285 286 str.append( "\r\n[" ); 287 str.append( start_date ); 288 str.append( "] Log File Opened for " ); 289 str.append( Constants.APP_NAME ); 290 str.append( " " ); 291 str.append( Constants.AZUREUS_VERSION ); 292 str.append( "\r\n" ); 293 } 294 295 if ( timeStamp != null ){ 296 297 str.append( timeStamp ); 298 } 299 300 str.append( _str ); 301 302 if ( !direct_writes ){ 303 304 if ( pending == null ){ 305 306 pending = new LinkedList<StringBuilder>(); 307 } 308 309 pending.add( str ); 310 311 pending_size += str.length(); 312 313 if ( pending_size > MAX_PENDING ){ 314 315 writePending(); 316 } 317 318 return; 319 } 320 321 write( str ); 322 } 323 } 324 325 private void write( StringBuilder str )326 write( 327 StringBuilder str ) 328 { 329 try{ 330 File log_file = getLogFile(); 331 332 /** 333 * log_file.length will return 0 if the file doesn't exist, so we don't need 334 * to explicitly check for its existence. 335 */ 336 337 if ( log_file.length() >= max_size ){ 338 339 if ( current_writer != null ){ 340 341 current_writer.close(); 342 343 current_writer = null; 344 } 345 346 first_file = !first_file; 347 348 log_file = getLogFile(); 349 350 // If the file doesn't exist, this will just return false. 351 352 log_file.delete(); 353 } 354 355 if ( current_writer == null ){ 356 357 current_writer = new PrintWriter( new OutputStreamWriter( new FileOutputStream( log_file, true ), "UTF-8" )); 358 } 359 360 current_writer.println( str ); 361 362 current_writer.flush(); 363 364 }catch( Throwable e ){ 365 366 }finally{ 367 368 if ( current_writer != null && close_pws ){ 369 370 current_writer.close(); 371 372 current_writer = null; 373 } 374 } 375 } 376 377 protected void writePending()378 writePending() 379 { 380 synchronized( this ){ 381 382 if ( pending == null ){ 383 384 return; 385 } 386 387 // System.out.println( getName() + ": flushing " + pending_size ); 388 389 try{ 390 File log_file = getLogFile(); 391 392 /** 393 * log_file.length will return 0 if the file doesn't exist, so we don't need 394 * to explicitly check for its existence. 395 */ 396 397 if ( log_file.length() >= max_size ){ 398 399 if ( current_writer != null ){ 400 401 current_writer.close(); 402 403 current_writer = null; 404 } 405 406 first_file = !first_file; 407 408 log_file = getLogFile(); 409 410 // If the file doesn't exist, this will just return false. 411 412 log_file.delete(); 413 } 414 415 if ( current_writer == null ){ 416 417 current_writer = new PrintWriter( new OutputStreamWriter( new FileOutputStream( log_file, true ), "UTF-8" )); 418 } 419 420 for ( StringBuilder str: pending ){ 421 422 current_writer.println( str ); 423 } 424 425 current_writer.flush(); 426 427 }catch( Throwable e ){ 428 429 }finally{ 430 431 direct_writes = true; 432 pending = null; 433 434 if ( current_writer != null && close_pws ){ 435 436 current_writer.close(); 437 438 current_writer = null; 439 } 440 } 441 } 442 } 443 444 private File getLogFile()445 getLogFile() 446 { 447 return( new File( debug_dir, getName() + "_" + (first_file?"1":"2") + ".log" )); 448 } 449 450 private static String format( int n )451 format( 452 int n ) 453 { 454 if (n < 10){ 455 456 return( "0" + n ); 457 } 458 459 return( String.valueOf(n)); 460 } 461 } 462