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 ServerLog()92 public ServerLog() { 93 // Debug log file. Whatever gets logged by us also makes its way into debug log. 94 } 95 setProperties(Properties configurationProperties)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 setStackIpAddress(String ipAddress)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 closeLogFile()173 public synchronized void closeLogFile() { 174 if (printWriter != null) { 175 printWriter.close(); 176 printWriter = null; 177 } 178 } 179 checkLogFile()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 */ needsLogging()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 */ setLogFileName(String name)293 public void setLogFileName(String name) { 294 logFileName = name; 295 } 296 297 /** 298 * return the name of the log file. 299 */ getLogFileName()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 */ logMessage(String message)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 logMessage(String message, String from, String to, boolean sender, String callId, String firstLine, String status, String tid, long time, long timestampVal)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 */ logMessage(SIPMessage message, String from, String to, boolean sender, long time)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 */ logMessage(SIPMessage message, String from, String to, String status, boolean sender, long time)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 */ logMessage(SIPMessage message, String from, String to, String status, boolean sender)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 logException(Exception ex)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 */ setTraceLevel(int level)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 */ getTraceLevel()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 */ setAuxInfo(String auxInfo)445 public void setAuxInfo(String auxInfo) { 446 this.auxInfo = auxInfo; 447 } 448 setSipStack(SipStack sipStack)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 setStackProperties(Properties stackProperties)458 public void setStackProperties(Properties stackProperties) { 459 setProperties(stackProperties); 460 } 461 setLevel(int jsipLoggingLevel)462 public void setLevel(int jsipLoggingLevel) { 463 464 } 465 466 } 467