001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.loggers; 028 import org.opends.messages.Message; 029 030 import java.io.File; 031 import java.io.IOException; 032 import java.util.*; 033 034 import org.opends.server.api.*; 035 import org.opends.server.core.DirectoryServer; 036 import org.opends.server.config.ConfigException; 037 import org.opends.server.types.*; 038 039 import static org.opends.messages.ConfigMessages.*; 040 import static org.opends.messages.LoggerMessages.*; 041 import org.opends.messages.Severity; 042 import org.opends.messages.Category; 043 import org.opends.server.admin.std.server.ErrorLogPublisherCfg; 044 import org.opends.server.admin.std.server.FileBasedErrorLogPublisherCfg; 045 import org.opends.server.admin.std.meta.ErrorLogPublisherCfgDefn; 046 import org.opends.server.admin.server.ConfigurationChangeListener; 047 import static org.opends.server.util.StaticUtils.getFileForPath; 048 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; 049 import org.opends.server.util.TimeThread; 050 import static org.opends.server.util.ServerConstants.*; 051 052 053 /** 054 * This class provides an implementation of an error log publisher. 055 */ 056 public class TextErrorLogPublisher 057 extends ErrorLogPublisher<FileBasedErrorLogPublisherCfg> 058 implements ConfigurationChangeListener<FileBasedErrorLogPublisherCfg> 059 { 060 private TextWriter writer; 061 062 private FileBasedErrorLogPublisherCfg currentConfig; 063 064 /** 065 * Returns an instance of the text error log publisher that will print 066 * all messages to the provided writer. This is used to print the messages 067 * to the console when the server starts up. 068 * 069 * @param writer The text writer where the message will be written to. 070 * @return The instance of the text error log publisher that will print 071 * all messages to standard out. 072 */ 073 public static TextErrorLogPublisher 074 getStartupTextErrorPublisher(TextWriter writer) 075 { 076 TextErrorLogPublisher startupPublisher = new TextErrorLogPublisher(); 077 startupPublisher.writer = writer; 078 079 startupPublisher.defaultSeverities.addAll(Arrays.asList(Severity.values())); 080 081 return startupPublisher; 082 } 083 084 /** 085 * {@inheritDoc} 086 */ 087 public void initializeErrorLogPublisher(FileBasedErrorLogPublisherCfg config) 088 throws ConfigException, InitializationException 089 { 090 File logFile = getFileForPath(config.getLogFile()); 091 FileNamingPolicy fnPolicy = new TimeStampNaming(logFile); 092 093 try 094 { 095 FilePermission perm = 096 FilePermission.decodeUNIXMode(config.getLogFilePermissions()); 097 098 LogPublisherErrorHandler errorHandler = 099 new LogPublisherErrorHandler(config.dn()); 100 101 boolean writerAutoFlush = 102 config.isAutoFlush() && !config.isAsynchronous(); 103 104 MultifileTextWriter writer = 105 new MultifileTextWriter("Multifile Text Writer for " + 106 config.dn().toNormalizedString(), 107 config.getTimeInterval(), 108 fnPolicy, 109 perm, 110 errorHandler, 111 "UTF-8", 112 writerAutoFlush, 113 config.isAppend(), 114 (int)config.getBufferSize()); 115 116 // Validate retention and rotation policies. 117 for(DN dn : config.getRotationPolicyDNs()) 118 { 119 writer.addRotationPolicy(DirectoryServer.getRotationPolicy(dn)); 120 } 121 122 for(DN dn: config.getRetentionPolicyDNs()) 123 { 124 writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); 125 } 126 127 if(config.isAsynchronous()) 128 { 129 this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for " + 130 config.dn().toNormalizedString(), config.getQueueSize(), 131 config.isAutoFlush(), 132 writer); 133 } 134 else 135 { 136 this.writer = writer; 137 } 138 } 139 catch(DirectoryException e) 140 { 141 Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get( 142 config.dn().toString(), String.valueOf(e)); 143 throw new InitializationException(message, e); 144 145 } 146 catch(IOException e) 147 { 148 Message message = ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE.get( 149 logFile.toString(), config.dn().toString(), String.valueOf(e)); 150 throw new InitializationException(message, e); 151 152 } 153 154 Set<ErrorLogPublisherCfgDefn.DefaultSeverity> defSevs = 155 config.getDefaultSeverity(); 156 if(defSevs.isEmpty()) 157 { 158 defaultSeverities.add(Severity.FATAL_ERROR); 159 defaultSeverities.add(Severity.SEVERE_ERROR); 160 defaultSeverities.add(Severity.SEVERE_WARNING); 161 } else 162 { 163 for(ErrorLogPublisherCfgDefn.DefaultSeverity defSev : defSevs) 164 { 165 if(defSev.toString().equalsIgnoreCase(LOG_SEVERITY_ALL)) 166 { 167 defaultSeverities.add(Severity.FATAL_ERROR); 168 defaultSeverities.add(Severity.INFORMATION); 169 defaultSeverities.add(Severity.MILD_ERROR); 170 defaultSeverities.add(Severity.MILD_WARNING); 171 defaultSeverities.add(Severity.NOTICE); 172 defaultSeverities.add(Severity.SEVERE_ERROR); 173 defaultSeverities.add(Severity.SEVERE_WARNING); 174 } 175 else if (defSev.toString().equalsIgnoreCase(LOG_SEVERITY_NONE)) 176 { 177 // don't add any severity 178 } 179 else 180 { 181 Severity errorSeverity = 182 Severity.parseString(defSev.name()); 183 if(errorSeverity != null) 184 { 185 defaultSeverities.add(errorSeverity); 186 } 187 } 188 } 189 } 190 191 for(String overrideSeverity : config.getOverrideSeverity()) 192 { 193 if(overrideSeverity != null) 194 { 195 int equalPos = overrideSeverity.indexOf('='); 196 if (equalPos < 0) 197 { 198 Message msg = 199 WARN_ERROR_LOGGER_INVALID_OVERRIDE_SEVERITY.get(overrideSeverity); 200 throw new ConfigException(msg); 201 202 } else 203 { 204 String categoryName = overrideSeverity.substring(0, equalPos); 205 categoryName = categoryName.replace("-", "_").toUpperCase(); 206 try 207 { 208 Category category = Category.valueOf(categoryName); 209 210 HashSet<Severity> severities = 211 new HashSet<Severity>(); 212 StringTokenizer sevTokenizer = 213 new StringTokenizer(overrideSeverity.substring(equalPos+1), ","); 214 while (sevTokenizer.hasMoreElements()) 215 { 216 String severityName = sevTokenizer.nextToken(); 217 severityName = severityName.replace("-", "_").toUpperCase(); 218 if(severityName.equalsIgnoreCase(LOG_SEVERITY_ALL)) 219 { 220 severities.add(Severity.FATAL_ERROR); 221 severities.add(Severity.INFORMATION); 222 severities.add(Severity.MILD_ERROR); 223 severities.add(Severity.MILD_WARNING); 224 severities.add(Severity.NOTICE); 225 severities.add(Severity.SEVERE_ERROR); 226 severities.add(Severity.SEVERE_WARNING); 227 } 228 else 229 { 230 try 231 { 232 Severity severity = 233 Severity.parseString(severityName); 234 235 severities.add(severity); 236 } 237 catch(Exception e) 238 { 239 Message msg = 240 WARN_ERROR_LOGGER_INVALID_SEVERITY.get(severityName); 241 throw new ConfigException(msg); 242 } 243 } 244 } 245 definedSeverities.put(category, severities); 246 } 247 catch(Exception e) 248 { 249 Message msg = WARN_ERROR_LOGGER_INVALID_CATEGORY.get(categoryName); 250 throw new ConfigException(msg); 251 } 252 } 253 } 254 } 255 256 currentConfig = config; 257 258 config.addFileBasedErrorChangeListener(this); 259 } 260 261 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override() 267 public boolean isConfigurationAcceptable(ErrorLogPublisherCfg configuration, 268 List<Message> unacceptableReasons) 269 { 270 FileBasedErrorLogPublisherCfg config = 271 (FileBasedErrorLogPublisherCfg) configuration; 272 273 return isConfigurationChangeAcceptable(config, unacceptableReasons); 274 } 275 276 /** 277 * {@inheritDoc} 278 */ 279 public boolean isConfigurationChangeAcceptable( 280 FileBasedErrorLogPublisherCfg config, List<Message> unacceptableReasons) 281 { 282 // Make sure the permission is valid. 283 try 284 { 285 FilePermission filePerm = 286 FilePermission.decodeUNIXMode(config.getLogFilePermissions()); 287 if(!filePerm.isOwnerWritable()) 288 { 289 Message message = ERR_CONFIG_LOGGING_INSANE_MODE.get( 290 config.getLogFilePermissions()); 291 unacceptableReasons.add(message); 292 return false; 293 } 294 } 295 catch(DirectoryException e) 296 { 297 Message message = ERR_CONFIG_LOGGING_MODE_INVALID.get( 298 config.getLogFilePermissions(), String.valueOf(e)); 299 unacceptableReasons.add(message); 300 return false; 301 } 302 303 for(String overrideSeverity : config.getOverrideSeverity()) 304 { 305 if(overrideSeverity != null) 306 { 307 int equalPos = overrideSeverity.indexOf('='); 308 if (equalPos < 0) 309 { 310 Message msg = WARN_ERROR_LOGGER_INVALID_OVERRIDE_SEVERITY.get( 311 overrideSeverity); 312 unacceptableReasons.add(msg); 313 return false; 314 315 } else 316 { 317 String categoryName = overrideSeverity.substring(0, equalPos); 318 categoryName = categoryName.replace("-", "_").toUpperCase(); 319 try 320 { 321 Category.valueOf(categoryName); 322 } 323 catch(Exception e) 324 { 325 Message msg = WARN_ERROR_LOGGER_INVALID_CATEGORY.get(categoryName); 326 unacceptableReasons.add(msg); 327 } 328 329 StringTokenizer sevTokenizer = 330 new StringTokenizer(overrideSeverity.substring(equalPos+1), ","); 331 while (sevTokenizer.hasMoreElements()) 332 { 333 String severityName = sevTokenizer.nextToken(); 334 severityName = severityName.replace("-", "_").toUpperCase(); 335 if(!severityName.equalsIgnoreCase(LOG_SEVERITY_ALL)) 336 { 337 try 338 { 339 Severity.parseString(severityName); 340 } 341 catch(Exception e) 342 { 343 Message msg = 344 WARN_ERROR_LOGGER_INVALID_SEVERITY.get(severityName); 345 unacceptableReasons.add(msg); 346 return false; 347 } 348 } 349 } 350 } 351 } 352 } 353 return true; 354 } 355 356 /** 357 * {@inheritDoc} 358 */ 359 public ConfigChangeResult applyConfigurationChange( 360 FileBasedErrorLogPublisherCfg config) 361 { 362 // Default result code. 363 ResultCode resultCode = ResultCode.SUCCESS; 364 boolean adminActionRequired = false; 365 ArrayList<Message> messages = new ArrayList<Message>(); 366 367 Set<ErrorLogPublisherCfgDefn.DefaultSeverity> defSevs = 368 config.getDefaultSeverity(); 369 defaultSeverities.clear(); 370 if(defSevs.isEmpty()) 371 { 372 defaultSeverities.add(Severity.FATAL_ERROR); 373 defaultSeverities.add(Severity.SEVERE_ERROR); 374 defaultSeverities.add(Severity.SEVERE_WARNING); 375 } else 376 { 377 for(ErrorLogPublisherCfgDefn.DefaultSeverity defSev : defSevs) 378 { 379 if(defSev.toString().equalsIgnoreCase(LOG_SEVERITY_ALL)) 380 { 381 defaultSeverities.add(Severity.FATAL_ERROR); 382 defaultSeverities.add(Severity.INFORMATION); 383 defaultSeverities.add(Severity.MILD_ERROR); 384 defaultSeverities.add(Severity.MILD_WARNING); 385 defaultSeverities.add(Severity.NOTICE); 386 defaultSeverities.add(Severity.SEVERE_ERROR); 387 defaultSeverities.add(Severity.SEVERE_WARNING); 388 } 389 else if (defSev.toString().equalsIgnoreCase(LOG_SEVERITY_NONE)) 390 { 391 // don't add any severity 392 } 393 else 394 { 395 Severity errorSeverity = 396 Severity.parseString(defSev.name()); 397 if(errorSeverity != null) 398 { 399 defaultSeverities.add(errorSeverity); 400 } 401 } 402 } 403 } 404 405 definedSeverities.clear(); 406 for(String overrideSeverity : config.getOverrideSeverity()) 407 { 408 if(overrideSeverity != null) 409 { 410 int equalPos = overrideSeverity.indexOf('='); 411 if (equalPos < 0) 412 { 413 Message msg = WARN_ERROR_LOGGER_INVALID_OVERRIDE_SEVERITY.get( 414 overrideSeverity); 415 resultCode = DirectoryServer.getServerErrorResultCode(); 416 messages.add(msg); 417 } else 418 { 419 String categoryName = overrideSeverity.substring(0, equalPos); 420 categoryName = categoryName.replace("-", "_").toUpperCase(); 421 try 422 { 423 Category category = Category.valueOf(categoryName); 424 425 HashSet<Severity> severities = 426 new HashSet<Severity>(); 427 StringTokenizer sevTokenizer = 428 new StringTokenizer(overrideSeverity.substring(equalPos+1), ","); 429 while (sevTokenizer.hasMoreElements()) 430 { 431 String severityName = sevTokenizer.nextToken(); 432 severityName = severityName.replace("-", "_").toUpperCase(); 433 if(severityName.equalsIgnoreCase(LOG_SEVERITY_ALL)) 434 { 435 severities.add(Severity.FATAL_ERROR); 436 severities.add(Severity.INFORMATION); 437 severities.add(Severity.MILD_ERROR); 438 severities.add(Severity.MILD_WARNING); 439 severities.add(Severity.NOTICE); 440 severities.add(Severity.SEVERE_ERROR); 441 severities.add(Severity.SEVERE_WARNING); 442 } 443 else 444 { 445 try 446 { 447 Severity severity = 448 Severity.parseString(severityName); 449 450 severities.add(severity); 451 } 452 catch(Exception e) 453 { 454 Message msg = 455 WARN_ERROR_LOGGER_INVALID_SEVERITY.get(severityName); 456 throw new ConfigException(msg); 457 } 458 } 459 } 460 definedSeverities.put(category, severities); 461 } 462 catch(Exception e) 463 { 464 Message msg = WARN_ERROR_LOGGER_INVALID_CATEGORY.get(categoryName); 465 resultCode = DirectoryServer.getServerErrorResultCode(); 466 messages.add(msg); 467 } 468 } 469 } 470 } 471 472 File logFile = getFileForPath(config.getLogFile()); 473 FileNamingPolicy fnPolicy = new TimeStampNaming(logFile); 474 475 try 476 { 477 FilePermission perm = 478 FilePermission.decodeUNIXMode(config.getLogFilePermissions()); 479 480 boolean writerAutoFlush = 481 config.isAutoFlush() && !config.isAsynchronous(); 482 483 TextWriter currentWriter; 484 // Determine the writer we are using. If we were writing asyncronously, 485 // we need to modify the underlaying writer. 486 if(writer instanceof AsyncronousTextWriter) 487 { 488 currentWriter = ((AsyncronousTextWriter)writer).getWrappedWriter(); 489 } 490 else 491 { 492 currentWriter = writer; 493 } 494 495 if(currentWriter instanceof MultifileTextWriter) 496 { 497 MultifileTextWriter mfWriter = (MultifileTextWriter)writer; 498 499 mfWriter.setNamingPolicy(fnPolicy); 500 mfWriter.setFilePermissions(perm); 501 mfWriter.setAppend(config.isAppend()); 502 mfWriter.setAutoFlush(writerAutoFlush); 503 mfWriter.setBufferSize((int)config.getBufferSize()); 504 mfWriter.setInterval(config.getTimeInterval()); 505 506 mfWriter.removeAllRetentionPolicies(); 507 mfWriter.removeAllRotationPolicies(); 508 509 for(DN dn : config.getRotationPolicyDNs()) 510 { 511 mfWriter.addRotationPolicy(DirectoryServer.getRotationPolicy(dn)); 512 } 513 514 for(DN dn: config.getRetentionPolicyDNs()) 515 { 516 mfWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn)); 517 } 518 519 if(writer instanceof AsyncronousTextWriter && !config.isAsynchronous()) 520 { 521 // The asynronous setting is being turned off. 522 AsyncronousTextWriter asyncWriter = ((AsyncronousTextWriter)writer); 523 writer = mfWriter; 524 asyncWriter.shutdown(false); 525 } 526 527 if(!(writer instanceof AsyncronousTextWriter) && 528 config.isAsynchronous()) 529 { 530 // The asynronous setting is being turned on. 531 AsyncronousTextWriter asyncWriter = 532 new AsyncronousTextWriter("Asyncronous Text Writer for " + 533 config.dn().toNormalizedString(), config.getQueueSize(), 534 config.isAutoFlush(), 535 mfWriter); 536 writer = asyncWriter; 537 } 538 539 if((currentConfig.isAsynchronous() && config.isAsynchronous()) && 540 (currentConfig.getQueueSize() != config.getQueueSize())) 541 { 542 adminActionRequired = true; 543 } 544 545 currentConfig = config; 546 } 547 } 548 catch(Exception e) 549 { 550 Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get( 551 config.dn().toString(), 552 stackTraceToSingleLineString(e)); 553 resultCode = DirectoryServer.getServerErrorResultCode(); 554 messages.add(message); 555 556 } 557 558 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 559 } 560 561 562 563 /** 564 * {@inheritDoc} 565 */ 566 public void close() 567 { 568 writer.shutdown(); 569 570 if(currentConfig != null) 571 { 572 currentConfig.removeFileBasedErrorChangeListener(this); 573 } 574 } 575 576 577 /** 578 * {@inheritDoc} 579 */ 580 public void logError(Message message) 581 { 582 Severity severity = message.getDescriptor().getSeverity(); 583 Category category = message.getDescriptor().getCategory(); 584 int msgId = message.getDescriptor().getId(); 585 HashSet<Severity> severities = definedSeverities.get(category); 586 if(severities == null) 587 { 588 severities = defaultSeverities; 589 } 590 591 if(severities.contains(severity)) 592 { 593 594 StringBuilder sb = new StringBuilder(); 595 sb.append("["); 596 sb.append(TimeThread.getLocalTime()); 597 sb.append("] category=").append(category). 598 append(" severity=").append(severity). 599 append(" msgID=").append(msgId). 600 append(" msg=").append(message); 601 602 writer.writeRecord(sb.toString()); 603 } 604 } 605 606 /** 607 * {@inheritDoc} 608 */ 609 public DN getDN() 610 { 611 if(currentConfig != null) 612 { 613 return currentConfig.dn(); 614 } 615 else 616 { 617 return null; 618 } 619 } 620 } 621