001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.config; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.logging.log4j.Level; 027import org.apache.logging.log4j.LogManager; 028import org.apache.logging.log4j.Marker; 029import org.apache.logging.log4j.core.Appender; 030import org.apache.logging.log4j.core.Core; 031import org.apache.logging.log4j.core.Filter; 032import org.apache.logging.log4j.core.LogEvent; 033import org.apache.logging.log4j.core.LoggerContext; 034import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender; 035import org.apache.logging.log4j.core.appender.FileAppender; 036import org.apache.logging.log4j.core.async.AsyncLoggerConfig; 037import org.apache.logging.log4j.core.async.AsyncLoggerContext; 038import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector; 039import org.apache.logging.log4j.core.config.plugins.Plugin; 040import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 041import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 042import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 043import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 044import org.apache.logging.log4j.core.config.plugins.PluginElement; 045import org.apache.logging.log4j.core.config.plugins.PluginFactory; 046import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 047import org.apache.logging.log4j.core.config.properties.PropertiesConfiguration; 048import org.apache.logging.log4j.core.filter.AbstractFilterable; 049import org.apache.logging.log4j.core.impl.DefaultLogEventFactory; 050import org.apache.logging.log4j.core.impl.LocationAware; 051import org.apache.logging.log4j.core.impl.LocationAwareLogEventFactory; 052import org.apache.logging.log4j.core.impl.Log4jLogEvent; 053import org.apache.logging.log4j.core.impl.LogEventFactory; 054import org.apache.logging.log4j.core.impl.ReusableLogEventFactory; 055import org.apache.logging.log4j.core.lookup.StrSubstitutor; 056import org.apache.logging.log4j.core.util.Booleans; 057import org.apache.logging.log4j.core.util.Constants; 058import org.apache.logging.log4j.core.util.Loader; 059import org.apache.logging.log4j.message.Message; 060import org.apache.logging.log4j.util.PerformanceSensitive; 061import org.apache.logging.log4j.util.PropertiesUtil; 062import org.apache.logging.log4j.util.StackLocatorUtil; 063import org.apache.logging.log4j.util.Strings; 064 065/** 066 * Logger object that is created via configuration. 067 */ 068@Plugin(name = "logger", category = Node.CATEGORY, printObject = true) 069public class LoggerConfig extends AbstractFilterable implements LocationAware { 070 071 public static final String ROOT = "root"; 072 private static LogEventFactory LOG_EVENT_FACTORY = null; 073 074 private List<AppenderRef> appenderRefs = new ArrayList<>(); 075 private final AppenderControlArraySet appenders = new AppenderControlArraySet(); 076 private final String name; 077 private LogEventFactory logEventFactory; 078 private Level level; 079 private boolean additive = true; 080 private boolean includeLocation = true; 081 private LoggerConfig parent; 082 private Map<Property, Boolean> propertiesMap; 083 private final List<Property> properties; 084 private final boolean propertiesRequireLookup; 085 private final Configuration config; 086 private final ReliabilityStrategy reliabilityStrategy; 087 088 static { 089 final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY); 090 if (factory != null) { 091 try { 092 final Class<?> clazz = Loader.loadClass(factory); 093 if (clazz != null && LogEventFactory.class.isAssignableFrom(clazz)) { 094 LOG_EVENT_FACTORY = (LogEventFactory) clazz.newInstance(); 095 } 096 } catch (final Exception ex) { 097 LOGGER.error("Unable to create LogEventFactory {}", factory, ex); 098 } 099 } 100 if (LOG_EVENT_FACTORY == null) { 101 LOG_EVENT_FACTORY = Constants.ENABLE_THREADLOCALS 102 ? new ReusableLogEventFactory() 103 : new DefaultLogEventFactory(); 104 } 105 } 106 107 @PluginBuilderFactory 108 public static <B extends Builder<B>> B newBuilder() { 109 return new Builder<B>().asBuilder(); 110 } 111 112 /** 113 * Builds LoggerConfig instances. 114 * 115 * @param <B> 116 * The type to build 117 */ 118 public static class Builder<B extends Builder<B>> 119 implements org.apache.logging.log4j.core.util.Builder<LoggerConfig> { 120 121 @PluginBuilderAttribute 122 private Boolean additivity; 123 @PluginBuilderAttribute 124 private Level level; 125 @PluginBuilderAttribute 126 private String levelAndRefs; 127 @PluginBuilderAttribute("name") 128 @Required(message = "Loggers cannot be configured without a name") 129 private String loggerName; 130 @PluginBuilderAttribute 131 private String includeLocation; 132 @PluginElement("AppenderRef") 133 private AppenderRef[] refs; 134 @PluginElement("Properties") 135 private Property[] properties; 136 @PluginConfiguration 137 private Configuration config; 138 @PluginElement("Filter") 139 private Filter filter; 140 141 public boolean isAdditivity() { 142 return additivity == null || additivity; 143 } 144 145 public B withAdditivity(boolean additivity) { 146 this.additivity = additivity; 147 return asBuilder(); 148 } 149 150 public Level getLevel() { 151 return level; 152 } 153 154 public B withLevel(Level level) { 155 this.level = level; 156 return asBuilder(); 157 } 158 159 public String getLevelAndRefs() { 160 return levelAndRefs; 161 } 162 163 public B withLevelAndRefs(String levelAndRefs) { 164 this.levelAndRefs = levelAndRefs; 165 return asBuilder(); 166 } 167 168 public String getLoggerName() { 169 return loggerName; 170 } 171 172 public B withLoggerName(String loggerName) { 173 this.loggerName = loggerName; 174 return asBuilder(); 175 } 176 177 public String getIncludeLocation() { 178 return includeLocation; 179 } 180 181 public B withIncludeLocation(String includeLocation) { 182 this.includeLocation = includeLocation; 183 return asBuilder(); 184 } 185 186 public AppenderRef[] getRefs() { 187 return refs; 188 } 189 190 public B withRefs(AppenderRef[] refs) { 191 this.refs = refs; 192 return asBuilder(); 193 } 194 195 public Property[] getProperties() { 196 return properties; 197 } 198 199 public B withProperties(Property[] properties) { 200 this.properties = properties; 201 return asBuilder(); 202 } 203 204 public Configuration getConfig() { 205 return config; 206 } 207 208 public B withConfig(Configuration config) { 209 this.config = config; 210 return asBuilder(); 211 } 212 213 public Filter getFilter() { 214 return filter; 215 } 216 217 public B withtFilter(Filter filter) { 218 this.filter = filter; 219 return asBuilder(); 220 } 221 222 @Override 223 public LoggerConfig build() { 224 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; 225 LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, config); 226 boolean useLocation = includeLocation(includeLocation, config); 227 return new LoggerConfig(name, container.refs, filter, container.level, isAdditivity(), properties, config, 228 useLocation); 229 } 230 231 @SuppressWarnings("unchecked") 232 public B asBuilder() { 233 return (B) this; 234 } 235 } 236 237 /** 238 * Default constructor. 239 */ 240 public LoggerConfig() { 241 this.logEventFactory = LOG_EVENT_FACTORY; 242 this.level = Level.ERROR; 243 this.name = Strings.EMPTY; 244 this.properties = null; 245 this.propertiesRequireLookup = false; 246 this.config = null; 247 this.reliabilityStrategy = new DefaultReliabilityStrategy(this); 248 } 249 250 /** 251 * Constructor that sets the name, level and additive values. 252 * 253 * @param name The Logger name. 254 * @param level The Level. 255 * @param additive true if the Logger is additive, false otherwise. 256 */ 257 public LoggerConfig(final String name, final Level level, final boolean additive) { 258 this.logEventFactory = LOG_EVENT_FACTORY; 259 this.name = name; 260 this.level = level; 261 this.additive = additive; 262 this.properties = null; 263 this.propertiesRequireLookup = false; 264 this.config = null; 265 this.reliabilityStrategy = new DefaultReliabilityStrategy(this); 266 } 267 268 protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter, 269 final Level level, final boolean additive, final Property[] properties, final Configuration config, 270 final boolean includeLocation) { 271 super(filter); 272 this.logEventFactory = LOG_EVENT_FACTORY; 273 this.name = name; 274 this.appenderRefs = appenders; 275 this.level = level; 276 this.additive = additive; 277 this.includeLocation = includeLocation; 278 this.config = config; 279 if (properties != null && properties.length > 0) { 280 this.properties = Collections.unmodifiableList(Arrays.asList(Arrays.copyOf( 281 properties, properties.length))); 282 } else { 283 this.properties = null; 284 } 285 this.propertiesRequireLookup = containsPropertyRequiringLookup(properties); 286 this.reliabilityStrategy = config.getReliabilityStrategy(this); 287 } 288 289 private static boolean containsPropertyRequiringLookup(final Property[] properties) { 290 if (properties == null) { 291 return false; 292 } 293 for (int i = 0; i < properties.length; i++) { 294 if (properties[i].isValueNeedsLookup()) { 295 return true; 296 } 297 } 298 return false; 299 } 300 301 @Override 302 public Filter getFilter() { 303 return super.getFilter(); 304 } 305 306 /** 307 * Returns the name of the LoggerConfig. 308 * 309 * @return the name of the LoggerConfig. 310 */ 311 public String getName() { 312 return name; 313 } 314 315 /** 316 * Sets the parent of this LoggerConfig. 317 * 318 * @param parent the parent LoggerConfig. 319 */ 320 public void setParent(final LoggerConfig parent) { 321 this.parent = parent; 322 } 323 324 /** 325 * Returns the parent of this LoggerConfig. 326 * 327 * @return the LoggerConfig that is the parent of this one. 328 */ 329 public LoggerConfig getParent() { 330 return this.parent; 331 } 332 333 /** 334 * Adds an Appender to the LoggerConfig. 335 * 336 * @param appender The Appender to add. 337 * @param level The Level to use. 338 * @param filter A Filter for the Appender reference. 339 */ 340 public void addAppender(final Appender appender, final Level level, final Filter filter) { 341 appenders.add(new AppenderControl(appender, level, filter)); 342 } 343 344 /** 345 * Removes the Appender with the specific name. 346 * 347 * @param name The name of the Appender. 348 */ 349 public void removeAppender(final String name) { 350 AppenderControl removed = null; 351 while ((removed = appenders.remove(name)) != null) { 352 cleanupFilter(removed); 353 } 354 } 355 356 /** 357 * Returns all Appenders as a Map. 358 * 359 * @return a Map with the Appender name as the key and the Appender as the value. 360 */ 361 public Map<String, Appender> getAppenders() { 362 return appenders.asMap(); 363 } 364 365 /** 366 * Removes all Appenders. 367 */ 368 protected void clearAppenders() { 369 do { 370 final AppenderControl[] original = appenders.clear(); 371 for (final AppenderControl ctl : original) { 372 cleanupFilter(ctl); 373 } 374 } while (!appenders.isEmpty()); 375 } 376 377 private void cleanupFilter(final AppenderControl ctl) { 378 final Filter filter = ctl.getFilter(); 379 if (filter != null) { 380 ctl.removeFilter(filter); 381 filter.stop(); 382 } 383 } 384 385 /** 386 * Returns the Appender references. 387 * 388 * @return a List of all the Appender names attached to this LoggerConfig. 389 */ 390 public List<AppenderRef> getAppenderRefs() { 391 return appenderRefs; 392 } 393 394 /** 395 * Sets the logging Level. 396 * 397 * @param level The logging Level. 398 */ 399 public void setLevel(final Level level) { 400 this.level = level; 401 } 402 403 /** 404 * Returns the logging Level. 405 * 406 * @return the logging Level. 407 */ 408 public Level getLevel() { 409 return level == null ? parent == null ? Level.ERROR : parent.getLevel() : level; 410 } 411 412 /** 413 * Returns the LogEventFactory. 414 * 415 * @return the LogEventFactory. 416 */ 417 public LogEventFactory getLogEventFactory() { 418 return logEventFactory; 419 } 420 421 /** 422 * Sets the LogEventFactory. Usually the LogEventFactory will be this LoggerConfig. 423 * 424 * @param logEventFactory the LogEventFactory. 425 */ 426 public void setLogEventFactory(final LogEventFactory logEventFactory) { 427 this.logEventFactory = logEventFactory; 428 } 429 430 /** 431 * Returns the valid of the additive flag. 432 * 433 * @return true if the LoggerConfig is additive, false otherwise. 434 */ 435 public boolean isAdditive() { 436 return additive; 437 } 438 439 /** 440 * Sets the additive setting. 441 * 442 * @param additive true if the LoggerConfig should be additive, false otherwise. 443 */ 444 public void setAdditive(final boolean additive) { 445 this.additive = additive; 446 } 447 448 /** 449 * Returns the value of logger configuration attribute {@code includeLocation}, or, if no such attribute was 450 * configured, {@code true} if logging is synchronous or {@code false} if logging is asynchronous. 451 * 452 * @return whether location should be passed downstream 453 */ 454 public boolean isIncludeLocation() { 455 return includeLocation; 456 } 457 458 /** 459 * Returns an unmodifiable map with the configuration properties, or {@code null} if this {@code LoggerConfig} does 460 * not have any configuration properties. 461 * <p> 462 * For each {@code Property} key in the map, the value is {@code true} if the property value has a variable that 463 * needs to be substituted. 464 * 465 * @return an unmodifiable map with the configuration properties, or {@code null} 466 * @see Configuration#getStrSubstitutor() 467 * @see StrSubstitutor 468 * @deprecated use {@link #getPropertyList()} instead 469 */ 470 // LOG4J2-157 471 @Deprecated 472 public Map<Property, Boolean> getProperties() { 473 if (properties == null) { 474 return null; 475 } 476 if (propertiesMap == null) { // lazily initialize: only used by user custom code, not by Log4j any more 477 final Map<Property, Boolean> result = new HashMap<>(properties.size() * 2); 478 for (int i = 0; i < properties.size(); i++) { 479 result.put(properties.get(i), Boolean.valueOf(properties.get(i).isValueNeedsLookup())); 480 } 481 propertiesMap = Collections.unmodifiableMap(result); 482 } 483 return propertiesMap; 484 } 485 486 /** 487 * Returns an unmodifiable list with the configuration properties, or {@code null} if this {@code LoggerConfig} does 488 * not have any configuration properties. 489 * <p> 490 * Each {@code Property} in the list has an attribute {@link Property#isValueNeedsLookup() valueNeedsLookup} that 491 * is {@code true} if the property value has a variable that needs to be substituted. 492 * 493 * @return an unmodifiable list with the configuration properties, or {@code null} 494 * @see Configuration#getStrSubstitutor() 495 * @see StrSubstitutor 496 * @since 2.7 497 */ 498 public List<Property> getPropertyList() { 499 return properties; 500 } 501 502 public boolean isPropertiesRequireLookup() { 503 return propertiesRequireLookup; 504 } 505 506 /** 507 * Logs an event. 508 * 509 * @param loggerName The name of the Logger. 510 * @param fqcn The fully qualified class name of the caller. 511 * @param marker A Marker or null if none is present. 512 * @param level The event Level. 513 * @param data The Message. 514 * @param t A Throwable or null. 515 */ 516 @PerformanceSensitive("allocation") 517 public void log(final String loggerName, final String fqcn, final Marker marker, final Level level, 518 final Message data, final Throwable t) { 519 final List<Property> props = getProperties(loggerName, fqcn, marker, level, data, t); 520 final LogEvent logEvent = logEventFactory.createEvent( 521 loggerName, marker, fqcn, location(fqcn), level, data, props, t); 522 try { 523 log(logEvent, LoggerConfigPredicate.ALL); 524 } finally { 525 // LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString()) 526 ReusableLogEventFactory.release(logEvent); 527 } 528 } 529 530 private StackTraceElement location(String fqcn) { 531 return requiresLocation() ? 532 StackLocatorUtil.calcLocation(fqcn) : null; 533 } 534 535 /** 536 * Logs an event. 537 * 538 * @param loggerName The name of the Logger. 539 * @param fqcn The fully qualified class name of the caller. 540 * @param location the location of the caller. 541 * @param marker A Marker or null if none is present. 542 * @param level The event Level. 543 * @param data The Message. 544 * @param t A Throwable or null. 545 */ 546 @PerformanceSensitive("allocation") 547 public void log(final String loggerName, final String fqcn, final StackTraceElement location, final Marker marker, 548 final Level level, final Message data, final Throwable t) { 549 final List<Property> props = getProperties(loggerName, fqcn, marker, level, data, t); 550 final LogEvent logEvent = logEventFactory.createEvent(loggerName, marker, fqcn, location, level, data, props, t); 551 try { 552 log(logEvent, LoggerConfigPredicate.ALL); 553 } finally { 554 // LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString()) 555 ReusableLogEventFactory.release(logEvent); 556 } 557 } 558 559 private List<Property> getProperties( 560 final String loggerName, 561 final String fqcn, 562 final Marker marker, 563 final Level level, 564 final Message data, 565 final Throwable t) { 566 List<Property> snapshot = properties; 567 if (snapshot == null || !propertiesRequireLookup) { 568 return snapshot; 569 } 570 return getPropertiesWithLookups(loggerName, fqcn, marker, level, data, t, snapshot); 571 } 572 573 private List<Property> getPropertiesWithLookups( 574 final String loggerName, 575 final String fqcn, 576 final Marker marker, 577 final Level level, 578 final Message data, 579 final Throwable t, 580 final List<Property> props) { 581 List<Property> results = new ArrayList<>(props.size()); 582 final LogEvent event = Log4jLogEvent.newBuilder() 583 .setMessage(data) 584 .setMarker(marker) 585 .setLevel(level) 586 .setLoggerName(loggerName) 587 .setLoggerFqcn(fqcn) 588 .setThrown(t) 589 .build(); 590 for (int i = 0; i < props.size(); i++) { 591 final Property prop = props.get(i); 592 final String value = prop.evaluate(config.getStrSubstitutor()); // since LOG4J2-1575 593 results.add(Property.createProperty(prop.getName(), prop.getRawValue(), value)); 594 } 595 return results; 596 } 597 598 /** 599 * Logs an event. 600 * 601 * @param event The log event. 602 */ 603 public void log(final LogEvent event) { 604 log(event, LoggerConfigPredicate.ALL); 605 } 606 607 /** 608 * Logs an event. 609 * 610 * @param event The log event. 611 * @param predicate predicate for which LoggerConfig instances to append to. 612 * A null value is equivalent to a true predicate. 613 */ 614 protected void log(final LogEvent event, final LoggerConfigPredicate predicate) { 615 if (!isFiltered(event)) { 616 processLogEvent(event, predicate); 617 } 618 } 619 620 /** 621 * Returns the object responsible for ensuring log events are delivered to a working appender, even during or after 622 * a reconfiguration. 623 * 624 * @return the object responsible for delivery of log events to the appender 625 */ 626 public ReliabilityStrategy getReliabilityStrategy() { 627 return reliabilityStrategy; 628 } 629 630 private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) { 631 event.setIncludeLocation(isIncludeLocation()); 632 if (predicate.allow(this)) { 633 callAppenders(event); 634 } 635 logParent(event, predicate); 636 } 637 638 @Override 639 public boolean requiresLocation() { 640 if (!includeLocation) { 641 return false; 642 } 643 AppenderControl[] controls = appenders.get(); 644 LoggerConfig loggerConfig = this; 645 while (loggerConfig != null) { 646 for (AppenderControl control : controls) { 647 Appender appender = control.getAppender(); 648 if (appender instanceof LocationAware && ((LocationAware) appender).requiresLocation()) { 649 return true; 650 } 651 } 652 if (loggerConfig.additive) { 653 loggerConfig = loggerConfig.parent; 654 if (loggerConfig != null) { 655 controls = loggerConfig.appenders.get(); 656 } 657 } else { 658 break; 659 } 660 } 661 return false; 662 } 663 664 private void logParent(final LogEvent event, final LoggerConfigPredicate predicate) { 665 if (additive && parent != null) { 666 parent.log(event, predicate); 667 } 668 } 669 670 @PerformanceSensitive("allocation") 671 protected void callAppenders(final LogEvent event) { 672 final AppenderControl[] controls = appenders.get(); 673 //noinspection ForLoopReplaceableByForEach 674 for (int i = 0; i < controls.length; i++) { 675 controls[i].callAppender(event); 676 } 677 } 678 679 @Override 680 public String toString() { 681 return Strings.isEmpty(name) ? ROOT : name; 682 } 683 684 /** 685 * Factory method to create a LoggerConfig. 686 * 687 * @param additivity True if additive, false otherwise. 688 * @param level The Level to be associated with the Logger. 689 * @param loggerName The name of the Logger. 690 * @param includeLocation whether location should be passed downstream 691 * @param refs An array of Appender names. 692 * @param properties Properties to pass to the Logger. 693 * @param config The Configuration. 694 * @param filter A Filter. 695 * @return A new LoggerConfig. 696 * @deprecated Deprecated in 2.7; use {@link #createLogger(boolean, Level, String, String, AppenderRef[], Property[], Configuration, Filter)} 697 */ 698 @Deprecated 699 public static LoggerConfig createLogger(final String additivity, 700 // @formatter:off 701 final Level level, 702 @PluginAttribute("name") final String loggerName, 703 final String includeLocation, 704 final AppenderRef[] refs, 705 final Property[] properties, 706 @PluginConfiguration final Configuration config, 707 final Filter filter) { 708 // @formatter:on 709 if (loggerName == null) { 710 LOGGER.error("Loggers cannot be configured without a name"); 711 return null; 712 } 713 714 final List<AppenderRef> appenderRefs = Arrays.asList(refs); 715 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; 716 final boolean additive = Booleans.parseBoolean(additivity, true); 717 718 return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config, 719 includeLocation(includeLocation, config)); 720 } 721 722 /** 723 * Factory method to create a LoggerConfig. 724 * 725 * @param additivity true if additive, false otherwise. 726 * @param level The Level to be associated with the Logger. 727 * @param loggerName The name of the Logger. 728 * @param includeLocation whether location should be passed downstream 729 * @param refs An array of Appender names. 730 * @param properties Properties to pass to the Logger. 731 * @param config The Configuration. 732 * @param filter A Filter. 733 * @return A new LoggerConfig. 734 * @since 2.6 735 */ 736 @Deprecated 737 public static LoggerConfig createLogger( 738 // @formatter:off 739 @PluginAttribute(value = "additivity", defaultBoolean = true) final boolean additivity, 740 @PluginAttribute("level") final Level level, 741 @Required(message = "Loggers cannot be configured without a name") @PluginAttribute("name") final String loggerName, 742 @PluginAttribute("includeLocation") final String includeLocation, 743 @PluginElement("AppenderRef") final AppenderRef[] refs, 744 @PluginElement("Properties") final Property[] properties, 745 @PluginConfiguration final Configuration config, 746 @PluginElement("Filter") final Filter filter 747 // @formatter:on 748 ) { 749 final String name = loggerName.equals(ROOT) ? Strings.EMPTY : loggerName; 750 return new LoggerConfig(name, Arrays.asList(refs), filter, level, additivity, properties, config, 751 includeLocation(includeLocation, config)); 752 } 753 754 /** 755 */ 756 protected static boolean includeLocation(final String includeLocationConfigValue) { 757 return includeLocation(includeLocationConfigValue, null); 758 } 759 760 // Note: for asynchronous loggers, includeLocation default is FALSE, 761 // for synchronous loggers, includeLocation default is TRUE. 762 protected static boolean includeLocation(final String includeLocationConfigValue, final Configuration configuration) { 763 if (includeLocationConfigValue == null) { 764 LoggerContext context = null; 765 if (configuration != null) { 766 context = configuration.getLoggerContext(); 767 } 768 if (context != null) { 769 return !(context instanceof AsyncLoggerContext); 770 } else { 771 return !AsyncLoggerContextSelector.isSelected(); 772 } 773 } 774 return Boolean.parseBoolean(includeLocationConfigValue); 775 } 776 777 protected final boolean hasAppenders() { 778 return !appenders.isEmpty(); 779 } 780 781 /** 782 * The root Logger. 783 */ 784 @Plugin(name = ROOT, category = Core.CATEGORY_NAME, printObject = true) 785 public static class RootLogger extends LoggerConfig { 786 787 @PluginBuilderFactory 788 public static <B extends Builder<B>> B newRootBuilder() { 789 return new Builder<B>().asBuilder(); 790 } 791 792 /** 793 * Builds LoggerConfig instances. 794 * 795 * @param <B> 796 * The type to build 797 */ 798 public static class Builder<B extends Builder<B>> 799 implements org.apache.logging.log4j.core.util.Builder<LoggerConfig> { 800 801 @PluginBuilderAttribute 802 private boolean additivity; 803 @PluginBuilderAttribute 804 private Level level; 805 @PluginBuilderAttribute 806 private String levelAndRefs; 807 @PluginBuilderAttribute 808 private String includeLocation; 809 @PluginElement("AppenderRef") 810 private AppenderRef[] refs; 811 @PluginElement("Properties") 812 private Property[] properties; 813 @PluginConfiguration 814 private Configuration config; 815 @PluginElement("Filter") 816 private Filter filter; 817 818 public boolean isAdditivity() { 819 return additivity; 820 } 821 822 public B withAdditivity(boolean additivity) { 823 this.additivity = additivity; 824 return asBuilder(); 825 } 826 827 public Level getLevel() { 828 return level; 829 } 830 831 public B withLevel(Level level) { 832 this.level = level; 833 return asBuilder(); 834 } 835 836 public String getLevelAndRefs() { 837 return levelAndRefs; 838 } 839 840 public B withLevelAndRefs(String levelAndRefs) { 841 this.levelAndRefs = levelAndRefs; 842 return asBuilder(); 843 } 844 845 public String getIncludeLocation() { 846 return includeLocation; 847 } 848 849 public B withIncludeLocation(String includeLocation) { 850 this.includeLocation = includeLocation; 851 return asBuilder(); 852 } 853 854 public AppenderRef[] getRefs() { 855 return refs; 856 } 857 858 public B withRefs(AppenderRef[] refs) { 859 this.refs = refs; 860 return asBuilder(); 861 } 862 863 public Property[] getProperties() { 864 return properties; 865 } 866 867 public B withProperties(Property[] properties) { 868 this.properties = properties; 869 return asBuilder(); 870 } 871 872 public Configuration getConfig() { 873 return config; 874 } 875 876 public B withConfig(Configuration config) { 877 this.config = config; 878 return asBuilder(); 879 } 880 881 public Filter getFilter() { 882 return filter; 883 } 884 885 public B withtFilter(Filter filter) { 886 this.filter = filter; 887 return asBuilder(); 888 } 889 890 @Override 891 public LoggerConfig build() { 892 LevelAndRefs container = LoggerConfig.getLevelAndRefs(level, refs, levelAndRefs, config); 893 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, container.refs, filter, container.level, 894 additivity, properties, config, includeLocation(includeLocation, config)); 895 } 896 897 @SuppressWarnings("unchecked") 898 public B asBuilder() { 899 return (B) this; 900 } 901 } 902 903 904 @Deprecated 905 public static LoggerConfig createLogger( 906 // @formatter:off 907 @PluginAttribute("additivity") final String additivity, 908 @PluginAttribute("level") final Level level, 909 @PluginAttribute("includeLocation") final String includeLocation, 910 @PluginElement("AppenderRef") final AppenderRef[] refs, 911 @PluginElement("Properties") final Property[] properties, 912 @PluginConfiguration final Configuration config, 913 @PluginElement("Filter") final Filter filter) { 914 // @formatter:on 915 final List<AppenderRef> appenderRefs = Arrays.asList(refs); 916 final Level actualLevel = level == null ? Level.ERROR : level; 917 final boolean additive = Booleans.parseBoolean(additivity, true); 918 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive, 919 properties, config, includeLocation(includeLocation, config)); 920 } 921 } 922 923 protected static LevelAndRefs getLevelAndRefs(Level level, AppenderRef[] refs, String levelAndRefs, 924 Configuration config) { 925 LevelAndRefs result = new LevelAndRefs(); 926 if (levelAndRefs != null) { 927 if (config instanceof PropertiesConfiguration) { 928 if (level != null) { 929 LOGGER.warn("Level is ignored when levelAndRefs syntax is used."); 930 } 931 if (refs != null && refs.length > 0) { 932 LOGGER.warn("Appender references are ignored when levelAndRefs syntax is used"); 933 } 934 final String[] parts = Strings.splitList(levelAndRefs); 935 result.level = Level.getLevel(parts[0]); 936 if (parts.length > 1) { 937 List<AppenderRef> refList = new ArrayList<>(); 938 Arrays.stream(parts).skip(1).forEach((ref) -> 939 refList.add(AppenderRef.createAppenderRef(ref, null, null))); 940 result.refs = refList; 941 } 942 } else { 943 LOGGER.warn("levelAndRefs are only allowed in a properties configuration. The value is ignored."); 944 result.level = level; 945 result.refs = Arrays.asList(refs); 946 } 947 } else { 948 result.level = level; 949 result.refs = Arrays.asList(refs); 950 } 951 return result; 952 } 953 954 protected static class LevelAndRefs { 955 public Level level; 956 public List<AppenderRef> refs; 957 } 958 959 protected enum LoggerConfigPredicate { 960 ALL() { 961 @Override 962 boolean allow(final LoggerConfig config) { 963 return true; 964 } 965 }, 966 ASYNCHRONOUS_ONLY() { 967 @Override 968 boolean allow(final LoggerConfig config) { 969 return config instanceof AsyncLoggerConfig; 970 } 971 }, 972 SYNCHRONOUS_ONLY() { 973 @Override 974 boolean allow(final LoggerConfig config) { 975 return !ASYNCHRONOUS_ONLY.allow(config); 976 } 977 }; 978 979 abstract boolean allow(LoggerConfig config); 980 } 981}