All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pmw.tinylog.Configuration Maven / Gradle / Ivy

There is a newer version: 1.3.6
Show newest version
/*
 * Copyright 2012 Martin Winandy
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package org.pmw.tinylog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.pmw.tinylog.writers.LogEntryValue;
import org.pmw.tinylog.writers.Writer;

/**
 * Configuration for {@link org.pmw.tinylog.Logger Logger}. Use {@link org.pmw.tinylog.Configurator Configurator} to
 * create a configuration.
 */
public final class Configuration {
	
	private static final Level DEFAULT_LEVEL = Level.INFO;
	private static final String DEFAULT_FORMAT_PATTERN = "{date} [{thread}] {class}.{method}()\n{level}: {message}";
	private static final int DEFAULT_MAX_STACK_TRACE_ELEMENTS = 40;

	private final Configurator configurator;
	
	private final Level level;
	private final Level lowestLevel;
	private final Map customLevels;
	private final String formatPattern;
	private final Locale locale;
	private final List writers;
	private final WritingThread writingThread;
	private final int maxStackTraceElements;

	private final Map effectiveWriters;
	private final Map[]> effectiveFormatTokens;
	private final Map> requiredLogEntryValues;
	private final Map requiredStackTraceInformation;

	/**
	 * @param configurator
	 *            Copy of based configurator
	 * @param level
	 *            Severity level
	 * @param customLevels
	 *            Custom severity levels for specific packages and classes
	 * @param formatPattern
	 *            Format pattern for log entries
	 * @param locale
	 *            Locale for format pattern
	 * @param writerDefinitions
	 *            Writer definitions (can be empty to disable any output)
	 * @param writingThread
	 *            Writing thread (can be null to write log entries synchronously)
	 * @param maxStackTraceElements
	 *            Limit of stack traces for exceptions
	 */
	Configuration(final Configurator configurator, final Level level, final Map customLevels, final String formatPattern, final Locale locale,
			final List writerDefinitions, final WritingThread writingThread, final Integer maxStackTraceElements) {
		this.configurator = configurator;
		
		this.level = level == null ? getLevel(writerDefinitions) : level;
		this.lowestLevel = getLowestLevel(this.level, customLevels, writerDefinitions);
		this.customLevels = customLevels;
		this.formatPattern = formatPattern == null ? DEFAULT_FORMAT_PATTERN : formatPattern;
		this.locale = locale == null ? Locale.getDefault() : locale;
		this.writers = getWriters(writerDefinitions);
		this.writingThread = writingThread;
		this.maxStackTraceElements = maxStackTraceElements == null ? DEFAULT_MAX_STACK_TRACE_ELEMENTS : maxStackTraceElements;

		this.effectiveWriters = getEffectiveWriters(writerDefinitions);
		this.effectiveFormatTokens = getEffectiveFormatTokens(writerDefinitions, this.formatPattern, this.locale, this.maxStackTraceElements);
		this.requiredLogEntryValues = getRequiredLogEntryValues(effectiveWriters, effectiveFormatTokens);
		this.requiredStackTraceInformation = getRequiredStackTraceInformation(requiredLogEntryValues, customLevels);
	}

	/**
	 * Get the global severity level.
	 *
	 * @return Global severity level
	 */
	public Level getLevel() {
		return level;
	}

	/**
	 * Check if there are custom severity levels.
	 *
	 * @return true if custom severity levels exist, false if not
	 */
	public boolean hasCustomLevels() {
		return !customLevels.isEmpty();
	}

	/**
	 * Get the severity level for a package or class.
	 *
	 * @param packageOrClass
	 *            Name of the package respectively class
	 *
	 * @return Severity level for the package respectively class
	 */
	public Level getLevel(final String packageOrClass) {
		String key = packageOrClass;
		while (true) {
			Level customLevel = customLevels.get(key);
			if (customLevel != null) {
				return customLevel;
			}
			int index = key.lastIndexOf('.');
			if (index > 0) {
				key = key.substring(0, index);
			} else {
				return level;
			}
		}
	}

	/**
	 * Get the format pattern for log entries.
	 *
	 * @return Format pattern for log entries
	 */
	public String getFormatPattern() {
		return formatPattern;
	}

	/**
	 * Get the locale that is used to render format patterns for log entries.
	 *
	 * @return Locale for format pattern
	 */
	public Locale getLocale() {
		return locale;
	}

	/**
	 * Get the writers to output created log entries.
	 *
	 * @return Writers to output log entries
	 */
	public List getWriters() {
		return writers;
	}

	/**
	 * Get the writing thread (writes log entries asynchronously).
	 *
	 * @return Writing thread
	 */
	public WritingThread getWritingThread() {
		return writingThread;
	}

	/**
	 * Get the limit of stack traces for exceptions.
	 *
	 * @return Limit of stack traces
	 */
	public int getMaxStackTraceElements() {
		return maxStackTraceElements;
	}
	
	/**
	 * Get a new configurator, based on this configuration.
	 * @return New configurator
	 */
	Configurator getConfigurator() {
		return configurator.copy();
	}

	/**
	 * Fast check if output is possible.
	 *
	 * @param level
	 *            Severity level to check
	 * @return true if log entries with the defined severity level can be output, false if not
	 */
	boolean isOutputPossible(final Level level) {
		return lowestLevel.ordinal() <= level.ordinal();
	}

	/**
	 * Get the effective writers to be used by the logger.
	 *
	 * @param level
	 *            Severity level of log entry
	 * @return Effective writers
	 */
	Writer[] getEffectiveWriters(final Level level) {
		return effectiveWriters.get(level);
	}

	/**
	 * Get the effective format tokens for all effective writers to be used by the logger.
	 *
	 * @param level
	 *            Severity level of log entry
	 * @return Effective format tokens
	 */
	List[] getEffectiveFormatTokens(final Level level) {
		return effectiveFormatTokens.get(level);
	}

	/**
	 * Get all log entry values that are required by the writers.
	 *
	 * @param level
	 *            Severity level of log entry
	 * @return Required values for log entry
	 */
	Set getRequiredLogEntryValues(final Level level) {
		return requiredLogEntryValues.get(level);
	}

	/**
	 * Get the required stack trace information.
	 *
	 * @param level
	 *            Severity level of log entry
	 * @return Required stack trace information
	 */
	StackTraceInformation getRequiredStackTraceInformation(final Level level) {
		return requiredStackTraceInformation.get(level);
	}

	private static Level getLevel(final List definitions) {
		Level level = null;
		for (WriterDefinition definition : definitions) {
			if (definition.getLevel() != null) {
				if (level == null || definition.getLevel().ordinal() < level.ordinal()) {
					level = definition.getLevel();
				}
			}
		}
		return level == null ? DEFAULT_LEVEL : level;
	}

	private static Level getLowestLevel(final Level level, final Map customLevels, final List definitions) {
		Level lowestLevel = level;
		for (Level customLevel : customLevels.values()) {
			if (lowestLevel.ordinal() > customLevel.ordinal()) {
				lowestLevel = customLevel;
			}
		}
		
		Level writerOutput = Level.OFF;
		for (WriterDefinition definition : definitions) {
			Level definitionLevel = definition.getLevel();
			if (definitionLevel == null) {
				definitionLevel = lowestLevel;
			}
			if (definitionLevel.ordinal() <= writerOutput.ordinal()) {
				writerOutput = definitionLevel;
			}
		}
		
		return writerOutput.ordinal() > lowestLevel.ordinal() ? writerOutput : lowestLevel;
	}

	private static List getWriters(final List definitions) {
		List writers = new ArrayList();
		for (WriterDefinition definition : definitions) {
			writers.add(definition.getWriter());
		}
		return writers.isEmpty() ? Collections. emptyList() : writers;
	}

	private static Map getEffectiveWriters(final List definitions) {
		Map map = new EnumMap(Level.class);
		for (Level level : Level.values()) {
			List writers = new ArrayList();
			for (WriterDefinition definition : definitions) {
				Level definitionLevel = definition.getLevel();
				if (definitionLevel == null) {
					definitionLevel = Level.TRACE;
				}
				if (level.ordinal() >= definitionLevel.ordinal()) {
					writers.add(definition.getWriter());
				}
			}
			map.put(level, writers.toArray(new Writer[writers.size()]));
		}
		return map;
	}

	@SuppressWarnings("unchecked")
	private static Map[]> getEffectiveFormatTokens(final List definitions, final String globalFormatPattern,
			final Locale locale, final int maxStackTraceElements) {
		Map> cache = new HashMap>();
		Tokenizer tokenizer = new Tokenizer(locale, maxStackTraceElements);

		Map[]> map = new EnumMap[]>(Level.class);
		for (Level level : Level.values()) {
			List> formatTokensOfLevel = new ArrayList>();
			for (WriterDefinition definition : definitions) {
				Level definitionLevel = definition.getLevel();
				if (definitionLevel == null) {
					definitionLevel = Level.TRACE;
				}
				if (level.ordinal() >= definitionLevel.ordinal()) {
					Writer writer = definition.getWriter();
					if (cache.containsKey(writer)) {
						formatTokensOfLevel.add(cache.get(writer));
					} else {
						Set requiredLogEntryValuesOfWriter = writer.getRequiredLogEntryValues();
						if (requiredLogEntryValuesOfWriter == null || !requiredLogEntryValuesOfWriter.contains(LogEntryValue.RENDERED_LOG_ENTRY)) {
							formatTokensOfLevel.add(null);
							cache.put(writer, null);
						} else {
							String formatPattern = definition.getFormatPattern();
							if (formatPattern == null) {
								formatPattern = globalFormatPattern;
							}
							List formatTokens = tokenizer.parse(formatPattern);
							formatTokensOfLevel.add(formatTokens);
							cache.put(writer, formatTokens);
						}
					}
				}
			}
			map.put(level, formatTokensOfLevel.toArray(new List[formatTokensOfLevel.size()]));
		}
		return map;
	}

	private static Map> getRequiredLogEntryValues(final Map writersMap,
			final Map[]> formatTokensMap) {
		Map> map = new EnumMap>(Level.class);
		for (Entry entry : writersMap.entrySet()) {
			Level level = entry.getKey();
			Writer[] writers = entry.getValue();
			if (writers.length == 0) {
				map.put(level, Collections. emptySet());
			} else {
				List[] formatTokens = formatTokensMap.get(level);
				Set requiredLogEntryValues = EnumSet.noneOf(LogEntryValue.class);
				for (int i = 0; i < writers.length; ++i) {
					Set requiredLogEntryValuesOfWriter = writers[i].getRequiredLogEntryValues();
					if (requiredLogEntryValuesOfWriter != null) {
						if (requiredLogEntryValuesOfWriter.contains(LogEntryValue.RENDERED_LOG_ENTRY)) {
							for (Token token : formatTokens[i]) {
								for (LogEntryValue logEntryValue : token.getRequiredLogEntryValues()) {
									requiredLogEntryValuesOfWriter.add(logEntryValue);
								}
							}
						}
						requiredLogEntryValues.addAll(requiredLogEntryValuesOfWriter);
					}
				}
				if (requiredLogEntryValues.isEmpty()) {
					map.put(level, Collections. emptySet());
				} else {
					map.put(level, requiredLogEntryValues);
				}
			}
		}
		return map;
	}

	private static Map getRequiredStackTraceInformation(final Map> requiredLogEntryValues,
			final Map customLevels) {
		Map map = new EnumMap(Level.class);
		for (Entry> entry : requiredLogEntryValues.entrySet()) {
			Level level = entry.getKey();
			Set logEntryValues = entry.getValue();
			if (logEntryValues.contains(LogEntryValue.METHOD) || logEntryValues.contains(LogEntryValue.FILE) || logEntryValues.contains(LogEntryValue.LINE)) {
				map.put(level, StackTraceInformation.FULL);
			} else if (logEntryValues.contains(LogEntryValue.CLASS) || !customLevels.isEmpty()) {
				map.put(level, StackTraceInformation.CLASS_NAME);
			} else {
				map.put(level, StackTraceInformation.NONE);
			}
		}
		return map;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy