package org.tinylog;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Static logger for issuing log entries.
 */
public final class Logger {

	private static final ConcurrentMap<String, TaggedLogger> loggers = new ConcurrentHashMap<>();
	private static final TaggedLogger logger = new TaggedLogger(null);

	/** */
	private Logger() {
	}

	/**
	 * Retrieves a tagged logger instance. Category tags are case-sensitive. If a tagged logger does not yet exists for
	 * the passed tag, a new logger will be created. This method always returns the same logger instance for the same
	 * tag.
	 *
	 * @param tag The case-sensitive category tag of the requested logger, or {@code null} for receiving an untagged
	 *            logger
	 * @return Logger instance
	 */
	public static TaggedLogger tag(String tag) {
		if (tag == null || tag.isEmpty()) {
			return logger;
		} else {
			return loggers.computeIfAbsent(tag, TaggedLogger::new);
		}
	}

}

package org.tinylog;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Static logger for issuing log entries.
 */
public final class Logger {

	private static final ConcurrentMap<String, TaggedLogger> loggers = new ConcurrentHashMap<>();

	/** */
	private Logger() {
	}

	/**
	 * Retrieves a tagged logger instance. Category tags are case-sensitive. If a tagged logger does not yet exists for
	 * the passed tag, a new logger will be created. This method always returns the same logger instance for the same
	 * tag.
	 *
	 * @param tag The case-sensitive category tag of the requested logger, or {@code null} for receiving an untagged
	 *            logger
	 * @return Logger instance
	 */
	public static TaggedLogger tag(String tag) {
		if (tag == null || tag.isEmpty()) {
			return loggers.computeIfAbsent("", untagged -> new TaggedLogger(null));
		} else {
			return loggers.computeIfAbsent(tag, TaggedLogger::new);
		}
	}

}

Store untagged root logger in map together with all tagged loggers