1 /* 2 * Conditions Of Use 3 * 4 * This software was developed by employees of the National Institute of 5 * Standards and Technology (NIST), an agency of the Federal Government. 6 * Pursuant to title 15 Untied States Code Section 105, works of NIST 7 * employees are not subject to copyright protection in the United States 8 * and are considered to be in the public domain. As a result, a formal 9 * license is not needed to use the software. 10 * 11 * This software is provided by NIST as a service and is expressly 12 * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15 * AND DATA ACCURACY. NIST does not warrant or make any representations 16 * regarding the use of the software or the results thereof, including but 17 * not limited to the correctness, accuracy, reliability or usefulness of 18 * the software. 19 * 20 * Permission to use this software is contingent upon your acceptance 21 * of the terms of this agreement 22 * 23 * . 24 * 25 */ 26 /******************************************************************************* 27 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * 28 ******************************************************************************/ 29 30 package gov.nist.javax.sip.stack; 31 32 import gov.nist.core.ServerLogger; 33 import gov.nist.core.StackLogger; 34 import gov.nist.javax.sip.LogRecord; 35 import gov.nist.javax.sip.header.CallID; 36 import gov.nist.javax.sip.message.SIPMessage; 37 38 import java.io.File; 39 import java.io.FileWriter; 40 import java.io.IOException; 41 import java.io.PrintWriter; 42 import java.util.Properties; 43 44 import javax.sip.SipStack; 45 import javax.sip.header.TimeStampHeader; 46 47 // BEGIN android-deleted 48 // import org.apache.log4j.Level; 49 // import org.apache.log4j.Logger; 50 // END android-deleted 51 52 /** 53 * Log file wrapper class. Log messages into the message trace file and also write the log into 54 * the debug file if needed. This class keeps an XML formatted trace around for later access via 55 * RMI. The trace can be viewed with a trace viewer (see tools.traceviewerapp). 56 * 57 * @version 1.2 $Revision: 1.39 $ $Date: 2009/11/11 14:00:58 $ 58 * 59 * @author M. Ranganathan <br/> 60 * 61 * 62 */ 63 public class ServerLog implements ServerLogger { 64 65 private boolean logContent; 66 67 protected StackLogger stackLogger; 68 69 /** 70 * Name of the log file in which the trace is written out (default is null) 71 */ 72 private String logFileName; 73 74 /** 75 * Print writer that is used to write out the log file. 76 */ 77 private PrintWriter printWriter; 78 79 /** 80 * Set auxililary information to log with this trace. 81 */ 82 private String auxInfo; 83 84 private String description; 85 86 private String stackIpAddress; 87 88 private SIPTransactionStack sipStack; 89 90 private Properties configurationProperties; 91 92 public ServerLog() { 93 // Debug log file. Whatever gets logged by us also makes its way into debug log. 94 } 95 96 private void setProperties(Properties configurationProperties) { 97 this.configurationProperties = configurationProperties; 98 // Set a descriptive name for the message trace logger. 99 this.description = configurationProperties.getProperty("javax.sip.STACK_NAME"); 100 this.stackIpAddress = configurationProperties.getProperty("javax.sip.IP_ADDRESS"); 101 this.logFileName = configurationProperties.getProperty("gov.nist.javax.sip.SERVER_LOG"); 102 String logLevel = configurationProperties.getProperty("gov.nist.javax.sip.TRACE_LEVEL"); 103 String logContent = configurationProperties 104 .getProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT"); 105 106 this.logContent = (logContent != null && logContent.equals("true")); 107 108 if (logLevel != null) { 109 if (logLevel.equals("LOG4J")) { 110 // if TRACE_LEVEL property is specified as 111 // "LOG4J" then, set the traceLevel based on 112 // the log4j effective log level. 113 114 // check whether a Log4j logger name has been 115 // specified. if not, use the stack name as the default 116 // logger name. 117 118 // BEGIN android-deleted 119 /* 120 Logger logger = Logger.getLogger(configurationProperties.getProperty( 121 "gov.nist.javax.sip.LOG4J_LOGGER_NAME", this.description)); 122 Level level = logger.getEffectiveLevel(); 123 if (level == Level.OFF) { 124 this.setTraceLevel(0); 125 } else if (level.isGreaterOrEqual(Level.DEBUG)) { 126 this.setTraceLevel(TRACE_DEBUG); 127 } else if (level.isGreaterOrEqual(Level.INFO)) { 128 this.setTraceLevel(TRACE_MESSAGES); 129 } else if (level.isGreaterOrEqual(Level.WARN)) { 130 this.setTraceLevel(TRACE_EXCEPTION); 131 } 132 */ 133 // END android-deleted 134 } else { 135 try { 136 int ll; 137 if (logLevel.equals("DEBUG")) { 138 ll = TRACE_DEBUG; 139 } else if (logLevel.equals("INFO")) { 140 ll = TRACE_MESSAGES; 141 } else if (logLevel.equals("ERROR")) { 142 ll = TRACE_EXCEPTION; 143 } else if (logLevel.equals("NONE") || logLevel.equals("OFF")) { 144 ll = TRACE_NONE; 145 } else { 146 ll = Integer.parseInt(logLevel); 147 } 148 149 this.setTraceLevel(ll); 150 } catch (NumberFormatException ex) { 151 System.out.println("ServerLog: WARNING Bad integer " + logLevel); 152 System.out.println("logging dislabled "); 153 this.setTraceLevel(0); 154 } 155 } 156 } 157 checkLogFile(); 158 159 } 160 161 public void setStackIpAddress(String ipAddress) { 162 this.stackIpAddress = ipAddress; 163 } 164 165 // public static boolean isWebTesterCatchException=false; 166 // public static String webTesterLogFile=null; 167 168 /** 169 * default trace level 170 */ 171 protected int traceLevel = TRACE_MESSAGES; 172 173 public synchronized void closeLogFile() { 174 if (printWriter != null) { 175 printWriter.close(); 176 printWriter = null; 177 } 178 } 179 180 public void checkLogFile() { 181 if (logFileName == null || traceLevel < TRACE_MESSAGES) { 182 // Dont create a log file if tracing is 183 // disabled. 184 return; 185 } 186 try { 187 File logFile = new File(logFileName); 188 if (!logFile.exists()) { 189 logFile.createNewFile(); 190 printWriter = null; 191 } 192 // Append buffer to the end of the file unless otherwise specified 193 // by the user. 194 if (printWriter == null) { 195 boolean overwrite = Boolean.valueOf( 196 configurationProperties.getProperty( 197 "gov.nist.javax.sip.SERVER_LOG_OVERWRITE")); 198 199 FileWriter fw = new FileWriter(logFileName, !overwrite); 200 201 printWriter = new PrintWriter(fw, true); 202 printWriter.println("<!-- " 203 + "Use the Trace Viewer in src/tools/tracesviewer to" 204 + " view this trace \n" 205 + "Here are the stack configuration properties \n" 206 + "javax.sip.IP_ADDRESS= " 207 + configurationProperties.getProperty("javax.sip.IP_ADDRESS") + "\n" 208 + "javax.sip.STACK_NAME= " 209 + configurationProperties.getProperty("javax.sip.STACK_NAME") + "\n" 210 + "javax.sip.ROUTER_PATH= " 211 + configurationProperties.getProperty("javax.sip.ROUTER_PATH") + "\n" 212 + "javax.sip.OUTBOUND_PROXY= " 213 + configurationProperties.getProperty("javax.sip.OUTBOUND_PROXY") + "\n" 214 + "-->"); 215 printWriter.println("<description\n logDescription=\"" + description 216 + "\"\n name=\"" 217 + configurationProperties.getProperty("javax.sip.STACK_NAME") 218 + "\"\n auxInfo=\"" + auxInfo + "\"/>\n "); 219 if (auxInfo != null) { 220 221 if (sipStack.isLoggingEnabled()) { 222 stackLogger 223 .logDebug("Here are the stack configuration properties \n" 224 + "javax.sip.IP_ADDRESS= " 225 + configurationProperties 226 .getProperty("javax.sip.IP_ADDRESS") 227 + "\n" 228 + "javax.sip.ROUTER_PATH= " 229 + configurationProperties 230 .getProperty("javax.sip.ROUTER_PATH") 231 + "\n" 232 + "javax.sip.OUTBOUND_PROXY= " 233 + configurationProperties 234 .getProperty("javax.sip.OUTBOUND_PROXY") 235 + "\n" 236 + "gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS= " 237 + configurationProperties 238 .getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS") 239 + "\n" 240 + "gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS= " 241 + configurationProperties 242 .getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS") 243 + "\n" 244 + "gov.nist.javax.sip.REENTRANT_LISTENER= " 245 + configurationProperties 246 .getProperty("gov.nist.javax.sip.REENTRANT_LISTENER") 247 + "gov.nist.javax.sip.THREAD_POOL_SIZE= " 248 + configurationProperties 249 .getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE") 250 + "\n"); 251 stackLogger.logDebug(" ]]> "); 252 stackLogger.logDebug("</debug>"); 253 stackLogger.logDebug("<description\n logDescription=\"" + description 254 + "\"\n name=\"" + stackIpAddress + "\"\n auxInfo=\"" + auxInfo 255 + "\"/>\n "); 256 stackLogger.logDebug("<debug>"); 257 stackLogger.logDebug("<![CDATA[ "); 258 } 259 } else { 260 261 if (sipStack.isLoggingEnabled()) { 262 stackLogger.logDebug("Here are the stack configuration properties \n" 263 + configurationProperties + "\n"); 264 stackLogger.logDebug(" ]]>"); 265 stackLogger.logDebug("</debug>"); 266 stackLogger.logDebug("<description\n logDescription=\"" + description 267 + "\"\n name=\"" + stackIpAddress + "\" />\n"); 268 stackLogger.logDebug("<debug>"); 269 stackLogger.logDebug("<![CDATA[ "); 270 } 271 } 272 } 273 } catch (IOException ex) { 274 275 } 276 } 277 278 /** 279 * Global check for whether to log or not. To minimize the time return false here. 280 * 281 * @return true -- if logging is globally enabled and false otherwise. 282 * 283 */ 284 public boolean needsLogging() { 285 return logFileName != null; 286 } 287 288 /** 289 * Set the log file name 290 * 291 * @param name is the name of the log file to set. 292 */ 293 public void setLogFileName(String name) { 294 logFileName = name; 295 } 296 297 /** 298 * return the name of the log file. 299 */ 300 public String getLogFileName() { 301 return logFileName; 302 } 303 304 /** 305 * Log a message into the log file. 306 * 307 * @param message message to log into the log file. 308 */ 309 private void logMessage(String message) { 310 // String tname = Thread.currentThread().getName(); 311 checkLogFile(); 312 String logInfo = message; 313 if (printWriter != null) { 314 printWriter.println(logInfo); 315 } 316 if (sipStack.isLoggingEnabled()) { 317 stackLogger.logInfo(logInfo); 318 319 } 320 } 321 322 private void logMessage(String message, String from, String to, boolean sender, 323 String callId, String firstLine, String status, String tid, long time, 324 long timestampVal) { 325 326 LogRecord log = this.sipStack.logRecordFactory.createLogRecord(message, from, to, time, 327 sender, firstLine, tid, callId, timestampVal); 328 if (log != null) 329 logMessage(log.toString()); 330 } 331 332 /** 333 * Log a message into the log directory. 334 * 335 * @param message a SIPMessage to log 336 * @param from from header of the message to log into the log directory 337 * @param to to header of the message to log into the log directory 338 * @param sender is the server the sender 339 * @param time is the time to associate with the message. 340 */ 341 public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) { 342 checkLogFile(); 343 if (message.getFirstLine() == null) 344 return; 345 CallID cid = (CallID) message.getCallId(); 346 String callId = null; 347 if (cid != null) 348 callId = cid.getCallId(); 349 String firstLine = message.getFirstLine().trim(); 350 String inputText = (logContent ? message.encode() : message.encodeMessage()); 351 String tid = message.getTransactionId(); 352 TimeStampHeader tsHdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME); 353 long tsval = tsHdr == null ? 0 : tsHdr.getTime(); 354 logMessage(inputText, from, to, sender, callId, firstLine, null, tid, time, tsval); 355 } 356 357 /** 358 * Log a message into the log directory. 359 * 360 * @param message a SIPMessage to log 361 * @param from from header of the message to log into the log directory 362 * @param to to header of the message to log into the log directory 363 * @param status the status to log. 364 * @param sender is the server the sender or receiver (true if sender). 365 * @param time is the reception time. 366 */ 367 public void logMessage(SIPMessage message, String from, String to, String status, 368 boolean sender, long time) { 369 checkLogFile(); 370 CallID cid = (CallID) message.getCallId(); 371 String callId = null; 372 if (cid != null) 373 callId = cid.getCallId(); 374 String firstLine = message.getFirstLine().trim(); 375 String encoded = (logContent ? message.encode() : message.encodeMessage()); 376 String tid = message.getTransactionId(); 377 TimeStampHeader tshdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME); 378 long tsval = tshdr == null ? 0 : tshdr.getTime(); 379 logMessage(encoded, from, to, sender, callId, firstLine, status, tid, time, tsval); 380 } 381 382 /** 383 * Log a message into the log directory. Time stamp associated with the message is the current 384 * time. 385 * 386 * @param message a SIPMessage to log 387 * @param from from header of the message to log into the log directory 388 * @param to to header of the message to log into the log directory 389 * @param status the status to log. 390 * @param sender is the server the sender or receiver (true if sender). 391 */ 392 public void logMessage(SIPMessage message, String from, String to, String status, 393 boolean sender) { 394 logMessage(message, from, to, status, sender, System.currentTimeMillis()); 395 } 396 397 /** 398 * Log an exception stack trace. 399 * 400 * @param ex Exception to log into the log file 401 */ 402 403 public void logException(Exception ex) { 404 if (traceLevel >= TRACE_EXCEPTION) { 405 checkLogFile(); 406 ex.printStackTrace(); 407 if (printWriter != null) 408 ex.printStackTrace(printWriter); 409 410 } 411 } 412 413 /** 414 * Set the trace level for the stack. 415 * 416 * @param level -- the trace level to set. The following trace levels are supported: 417 * <ul> 418 * <li> 0 -- no tracing </li> 419 * 420 * <li> 16 -- trace messages only </li> 421 * 422 * <li> 32 Full tracing including debug messages. </li> 423 * 424 * </ul> 425 */ 426 public void setTraceLevel(int level) { 427 traceLevel = level; 428 } 429 430 /** 431 * Get the trace level for the stack. 432 * 433 * @return the trace level 434 */ 435 public int getTraceLevel() { 436 return traceLevel; 437 } 438 439 /** 440 * Set aux information. Auxiliary information may be associated with the log file. This is 441 * useful for remote logs. 442 * 443 * @param auxInfo -- auxiliary information. 444 */ 445 public void setAuxInfo(String auxInfo) { 446 this.auxInfo = auxInfo; 447 } 448 449 public void setSipStack(SipStack sipStack) { 450 if(sipStack instanceof SIPTransactionStack) { 451 this.sipStack = (SIPTransactionStack)sipStack; 452 this.stackLogger = this.sipStack.getStackLogger(); 453 } 454 else 455 throw new IllegalArgumentException("sipStack must be a SIPTransactionStack"); 456 } 457 458 public void setStackProperties(Properties stackProperties) { 459 setProperties(stackProperties); 460 } 461 462 public void setLevel(int jsipLoggingLevel) { 463 464 } 465 466 } 467