View Javadoc

    1   /*
    2    * Copyright (c) 2004-2013 QOS.ch
    3    * All rights reserved.
    4    *
    5    * Permission is hereby granted, free  of charge, to any person obtaining
    6    * a  copy  of this  software  and  associated  documentation files  (the
    7    * "Software"), to  deal in  the Software without  restriction, including
    8    * without limitation  the rights to  use, copy, modify,  merge, publish,
    9    * distribute,  sublicense, and/or sell  copies of  the Software,  and to
    10   * permit persons to whom the Software  is furnished to do so, subject to
    11   * the following conditions:
    12   *
    13   * The  above  copyright  notice  and  this permission  notice  shall  be
    14   * included in all copies or substantial portions of the Software.
    15   *
    16   * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
    17   * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
    18   * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
    19   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    20   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    21   * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
    22   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    23   *
    24   */
    25  package org.slf4j.impl;
    26
    27  import org.slf4j.ILoggerFactory;
    28  import org.slf4j.Logger;
    29
    30  import java.util.concurrent.ConcurrentHashMap;
    31  import java.util.concurrent.ConcurrentMap;
    32
    33  /**
    34   * AndroidLoggerFactory is an implementation of {@link ILoggerFactory} returning
    35   * the appropriately named {@link AndroidLoggerFactory} instance.
    36   *
    37   * @author Andrey Korzhevskiy <a.korzhevskiy@gmail.com>
    38   */
    39  class AndroidLoggerFactory implements ILoggerFactory {
    40      static final String ANONYMOUS_TAG = "null";
    41      static final int TAG_MAX_LENGTH = 23;
    42
    43      private final ConcurrentMap<String, Logger> loggerMap = new ConcurrentHashMap<String, Logger>();
    44
    45      /**
    46       * Return an appropriate {@link AndroidLoggerAdapter} instance by name.
    47       */
    48      public Logger getLogger(String name) {
    49          String tag = loggerNameToTag(name);
    50          Logger logger = loggerMap.get(tag);
    51          if (logger == null) {
    52              Logger newInstance = new AndroidLoggerAdapter(tag);
    53              Logger oldInstance = loggerMap.putIfAbsent(tag, newInstance);
    54              logger = oldInstance == null ? newInstance : oldInstance;
    55          }
    56          return logger;
    57      }
    58
    59      /**
    60       * Tag names cannot be longer than {@value #TAG_MAX_LENGTH} characters on Android platform.
    61       *
    62       * Returns the short logger tag (up to {@value #TAG_MAX_LENGTH} characters) for the given logger name.
    63       * Traditionally loggers are named by fully-qualified Java classes; this
    64       * method attempts to return a concise identifying part of such names.
    65       *
    66       * See also:
    67       * android/system/core/include/cutils/property.h
    68       * android/frameworks/base/core/jni/android_util_Log.cpp
    69       * dalvik.system.DalvikLogging
    70       *
    71       */
    72      static String loggerNameToTag(String loggerName) {
    73          // Anonymous logger
    74          if (loggerName == null) {
    75              return ANONYMOUS_TAG;
    76          }
    77
    78          int length = loggerName.length();
    79          if (length <= TAG_MAX_LENGTH) {
    80              return loggerName;
    81          }
    82
    83          int tagLength = 0;
    84          int lastTokenIndex = 0;
    85          int lastPeriodIndex;
    86          StringBuilder tagName = new StringBuilder(TAG_MAX_LENGTH + 3);
    87          while ((lastPeriodIndex = loggerName.indexOf('.', lastTokenIndex)) != -1) {
    88              tagName.append(loggerName.charAt(lastTokenIndex));
    89              // token of one character appended as is otherwise truncate it to one character
    90              int tokenLength = lastPeriodIndex - lastTokenIndex;
    91              if (tokenLength > 1) {
    92                  tagName.append('*');
    93              }
    94              tagName.append('.');
    95              lastTokenIndex = lastPeriodIndex + 1;
    96
    97              // check if name is already too long
    98              tagLength = tagName.length();
    99              if (tagLength > TAG_MAX_LENGTH) {
    100                 return getSimpleName(loggerName);
    101             }
    102         }
    103
    104         // Either we had no useful dot location at all
    105         // or last token would exceed TAG_MAX_LENGTH
    106         int tokenLength = length - lastTokenIndex;
    107         if (tagLength == 0 || (tagLength + tokenLength) > TAG_MAX_LENGTH) {
    108             return getSimpleName(loggerName);
    109         }
    110
    111         // last token (usually class name) appended as is
    112         tagName.append(loggerName, lastTokenIndex, length);
    113         return tagName.toString();
    114     }
    115
    116     private static String getSimpleName(String loggerName) {
    117         // Take leading part and append '*' to indicate that it was truncated
    118         int length = loggerName.length();
    119         int lastPeriodIndex = loggerName.lastIndexOf('.');
    120         return lastPeriodIndex != -1 && length - (lastPeriodIndex + 1) <= TAG_MAX_LENGTH ? loggerName.substring(lastPeriodIndex + 1) : '*' + loggerName
    121                         .substring(length - TAG_MAX_LENGTH + 1);
    122     }
    123 }