1f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
3f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * This program and the accompanying materials are made available under
4f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * the terms of the Common Public License v1.0 which accompanies this distribution,
5f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * and is available at http://www.eclipse.org/legal/cpl-v10.html
6f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
7f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * $Id: Logger.java,v 1.1.1.1.2.2 2004/07/16 23:32:29 vlad_r Exp $
8f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
9f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpackage com.vladium.logging;
10f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
11f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.PrintWriter;
12f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.StringWriter;
13f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.HashSet;
14f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.LinkedList;
15f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.NoSuchElementException;
16f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.Properties;
17f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.Set;
18f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.StringTokenizer;
19f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
20f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.AppLoggers;
21f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppConstants;
22f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.ClassLoaderResolver;
23f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Property;
24f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Strings;
25f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
26f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------
27f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/**
28f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * A simple Java version-independent logging framework. Each Logger is also
29f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * an immutable context that encapsulates configuration elements like the
30f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * logging verbosity level etc. In general, a Logger is looked up as an
31f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * inheritable thread-local piece of data. This decouples classes and
32f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * logging configurations in a way that seems difficult with log4j.<P>
33f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
34f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * Note that a given class is free to cache its context in an instance field
35f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * if the class is instantiated and used only on a single thread (or a set of
36f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * threads that are guaranteed to share the same logging context). [This is
37f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * different from the usual log4j pattern of caching a logger in a class static
38f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * field]. In other cases (e.g., the instrumentation runtime), it makes more
39f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * sense to scope a context to a single method invocation.<P>
40f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
41f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * Every log message is structured as follows:
42f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * <OL>
43f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *  <LI> message is prefixed with the prefix string set in the Logger if that is
44f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * not null;
45f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *  <LI> if the calling class could be identified and it supplied the calling
46f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * method name, the calling method is identified with all name components that
47f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * are not null;
48f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *  <LI> caller-supplied message is logged, if not null;
49f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *  <LI> caller-supplied Throwable is dumped starting with a new line, if not null.
50f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * </OL>
51f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
52f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * MT-safety: a given Logger instance will not get corrupted by concurrent
53f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * usage from multiple threads and guarantees that data written to the underlying
54f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * PrintWriter in a single log call will be done in one atomic print() step.
55f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
56f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * @see ILogLevels
57f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
58f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * @author (C) 2001, Vlad Roubtsov
59f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
60f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpublic
61f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectfinal class Logger implements ILogLevels
62f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project{
63f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // public: ................................................................
64f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
65f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // TODO: update javadoc for 'logCaller'
66f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // TODO: need isLoggable (Class)
67f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
68f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static Logger create (final int level, final PrintWriter out, final String prefix, final Set classMask)
69f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
70f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((level < NONE) || (level > ALL))
71f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalArgumentException ("invalid log level: " + level);
72f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
73f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((out == null) || out.checkError ())
74f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalArgumentException ("null or corrupt input: out");
75f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
76f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return new Logger (level, out, prefix, classMask);
77f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
78f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
79f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
80f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * This works as a cloning creator of sorts.
81f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
82f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param level
83f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param out
84f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param prefix
85f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param classMask
86f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param base
87f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @return
88f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
89f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static Logger create (final int level, final PrintWriter out, final String prefix, final Set classMask,
90f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                 final Logger base)
91f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
92f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (base == null)
93f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
94f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return create (level, out, prefix, classMask);
95f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
96f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
97f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
98f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int _level = level >= NONE
99f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                ? level
100f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                : base.m_level;
101f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
102f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final PrintWriter _out = (out != null) && ! out.checkError ()
103f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                ? out
104f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                : base.m_out;
105f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
106f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // TODO: do a better job of logger cloning
107f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final String _prefix = prefix;
108f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            final String _prefix = prefix != null
109f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                ? prefix
110f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                : base.m_prefix;
111f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
112f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final Set _classMask = classMask != null
113f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                ? classMask
114f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                : base.m_classMask;
115f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
116f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
117f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return new Logger (_level, _out, _prefix, _classMask);
118f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
119f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
120f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
121f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
122f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
123f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A quick method to determine if logging is enabled at a given level.
124f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * This method acquires no monitors and should be used when calling one of
125f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * log() or convenience logging methods directly incurs significant
126f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * parameter construction overhead.
127f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
128f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @see ILogLevels
129f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
130f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean isLoggable (final int level)
131f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
132f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (level <= m_level);
133f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
134f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
135f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
136f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to isLoggable(INFO).
137f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
138f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean atINFO ()
139f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
140f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (INFO <= m_level);
141f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
142f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
143f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
144f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to isLoggable(VERBOSE).
145f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
146f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean atVERBOSE ()
147f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
148f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (VERBOSE <= m_level);
149f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
150f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
151f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
152f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to isLoggable(TRACE1).
153f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
154f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean atTRACE1 ()
155f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
156f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (TRACE1 <= m_level);
157f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
158f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
159f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
160f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to isLoggable(TRACE2).
161f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
162f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean atTRACE2 ()
163f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
164f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (TRACE2 <= m_level);
165f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
166f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
167f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
168f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to isLoggable(TRACE3).
169f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
170f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final boolean atTRACE3 ()
171f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
172f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (TRACE3 <= m_level);
173f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
174f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
175f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
176f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
177f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method to log 'msg' from an anonymous calling method
178f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * at WARNING level.
179f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
180f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
181f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
182f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void warning (final String msg)
183f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
184f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (WARNING, null, msg, false);
185f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
186f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
187f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
188f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method to log 'msg' from an anonymous calling method
189f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * at INFO level.
190f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
191f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
192f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
193f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void info (final String msg)
194f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
195f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (INFO, null, msg, false);
196f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
197f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
198f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
199f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method to log 'msg' from an anonymous calling method
200f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * at VERBOSE level.
201f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
202f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
203f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
204f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void verbose (final String msg)
205f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
206f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (VERBOSE, null, msg, false);
207f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
208f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
209f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
210f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
211f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to log(TRACE1, method, msg).
212f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
213f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param method calling method name [ignored if null]
214f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
215f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
216f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void trace1 (final String method, final String msg)
217f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
218f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (TRACE1, method, msg, true);
219f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
220f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
221f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
222f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to log(TRACE2, method, msg).
223f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
224f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param method calling method name [ignored if null]
225f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
226f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
227f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void trace2 (final String method, final String msg)
228f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
229f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (TRACE2, method, msg, true);
230f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
231f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
232f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
233f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * A convenience method equivalent to log(TRACE3, method, msg).
234f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
235f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param method calling method name [ignored if null]
236f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
237f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
238f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void trace3 (final String method, final String msg)
239f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
240f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (TRACE3, method, msg, true);
241f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
242f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
243f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
244f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Logs 'msg' from an unnamed calling method.
245f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
246f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param level level to log at [the method does nothing if this is less
247f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * than the set level].
248f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
249f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
250f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void log (final int level, final String msg, final boolean logCaller)
251f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
252f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (level, null, msg, logCaller);
253f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
254f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
255f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
256f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Logs 'msg' from a given calling method.
257f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
258f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param level level to log at [the method does nothing if this is less
259f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * than the set level].
260f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param method calling method name [ignored if null]
261f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
262f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
263f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void log (final int level, final String method, final String msg, final boolean logCaller)
264f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
265f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (level, method, msg, logCaller);
266f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
267f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
268f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
269f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Logs 'msg' from an unnamed calling method followed by the 'throwable' stack
270f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * trace dump.
271f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
272f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param level level to log at [the method does nothing if this is less
273f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * than the set level].
274f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
275f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param throwable to dump after message [ignored if null]
276f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
277f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void log (final int level, final String msg, final Throwable throwable)
278f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
279f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (level, null, msg, throwable);
280f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
281f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
282f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
283f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Logs 'msg' from a given calling method followed by the 'throwable' stack
284f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * trace dump.
285f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
286f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param level level to log at [the method does nothing if this is less
287f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * than the set level].
288f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param method calling method name [ignored if null]
289f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param msg log message [ignored if null]
290f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param throwable to dump after message [ignored if null]
291f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
292f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public final void log (final int level, final String method, final String msg, final Throwable throwable)
293f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
294f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        _log (level, method, msg, throwable);
295f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
296f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
297f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
298f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
299f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Provides direct access to the PrintWriter used by this Logger.
300f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
301f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @return print writer used by this logger [never null]
302f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
303f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public PrintWriter getWriter ()
304f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
305f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return m_out;
306f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
307f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
308f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
309f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
310f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Returns the current top of the thread-local logger stack or the static
311f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Logger instance scoped to Logger.class if the stack is empty.
312f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
313f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @return current logger [never null]
314f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
315f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static Logger getLogger ()
316f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
317f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();
318f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
319f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [assertion: stack != null]
320f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
321f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (stack.isEmpty ())
322f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
323f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return STATIC_LOGGER;
324f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
325f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
326f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
327f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return (Logger) stack.getLast ();
328f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
329f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
330f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
331f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
332f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
333f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param ctx [may not be null]
334f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
335f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void push (final Logger ctx)
336f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
337f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (ctx == null)
338f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalArgumentException ("null input: ctx");
339f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
340f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();
341f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        stack.addLast (ctx);
342f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
343f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
344f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
345f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * Requiring a context parameter here helps enforce correct push/pop
346f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * nesting in the caller code.
347f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
348f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param ctx [may not be null]
349f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
350f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void pop (final Logger ctx)
351f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
352f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: add guards for making sure only the pushing thread is allowed to
353f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // execute this
354f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
355f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final LinkedList stack = (LinkedList) THREAD_LOCAL_STACK.get ();
356f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
357f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
358f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
359f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final Logger current = (Logger) stack.getLast ();
360f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (current != ctx)
361f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IllegalStateException ("invalid context being popped: " + ctx);
362f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
363f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            stack.removeLast ();
364f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            current.cleanup ();
365f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
366f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        catch (NoSuchElementException nsee)
367f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
368f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("empty logger context stack on thread [" + Thread.currentThread () + "]: " + nsee);
369f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
370f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
371f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
372f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
373f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static int stringToLevel (final String level)
374f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
375f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (ILogLevels.SEVERE_STRING.equalsIgnoreCase (level) || ILogLevels.SILENT_STRING.equalsIgnoreCase (level))
376f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.SEVERE;
377f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.WARNING_STRING.equalsIgnoreCase (level) || ILogLevels.QUIET_STRING.equalsIgnoreCase (level))
378f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.WARNING;
379f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.INFO_STRING.equalsIgnoreCase (level))
380f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.INFO;
381f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.VERBOSE_STRING.equalsIgnoreCase (level))
382f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.VERBOSE;
383f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.TRACE1_STRING.equalsIgnoreCase (level))
384f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.TRACE1;
385f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.TRACE2_STRING.equalsIgnoreCase (level))
386f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.TRACE2;
387f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.TRACE3_STRING.equalsIgnoreCase (level))
388f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.TRACE3;
389f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.NONE_STRING.equalsIgnoreCase (level))
390f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.NONE;
391f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (ILogLevels.ALL_STRING.equalsIgnoreCase (level))
392f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return ILogLevels.ALL;
393f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
394f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
395f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            int _level = Integer.MIN_VALUE;
396f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
397f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
398f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                _level = Integer.parseInt (level);
399f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
400f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            catch (Exception ignore) {}
401f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
402f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ((_level >= ILogLevels.NONE) && (_level <= ILogLevels.ALL))
403f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                return _level;
404f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else
405f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                return ILogLevels.INFO; // default to something middle of the ground
406f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
407f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
408f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
409f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // protected: .............................................................
410f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
411f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // package: ...............................................................
412f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
413f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // private: ...............................................................
414f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
415f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
416f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class ThreadLocalStack extends InheritableThreadLocal
417f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
418f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        protected Object initialValue ()
419f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
420f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return new LinkedList ();
421f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
422f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
423f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
424f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
425f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
426f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private Logger (final int level, final PrintWriter out, final String prefix, final Set classMask)
427f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
428f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_level = level;
429f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_out = out;
430f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_prefix = prefix;
431f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_classMask = classMask; // no defensive clone
432f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
433f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
434f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private void cleanup ()
435f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
436f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_out.flush ();
437f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
438f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
439f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private void _log (final int level, final String method,
440f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                       final String msg, final boolean logCaller)
441f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
442f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((level <= m_level) && (level >= SEVERE))
443f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
444f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final Class caller = logCaller ? ClassLoaderResolver.getCallerClass (2) : null;
445f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final StringBuffer buf = new StringBuffer (m_prefix != null ? m_prefix + ": " : "");
446f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
447f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ((caller != null) || (method != null))
448f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
449f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                buf.append ("[");
450f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
451f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (caller != null) // if the caller could not be determined, s_classMask is ignored
452f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
453f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    String callerName = caller.getName ();
454f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
455f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (callerName.startsWith (PREFIX_TO_STRIP))
456f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        callerName = callerName.substring (PREFIX_TO_STRIP_LENGTH);
457f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
458f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    String parentName = callerName;
459f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
460f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final int firstDollar = callerName.indexOf ('$');
461f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (firstDollar > 0) parentName = callerName.substring (0, firstDollar);
462f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
463f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if ((m_classMask == null) || m_classMask.contains (parentName))
464f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        buf.append (callerName);
465f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else
466f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        return;
467f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
468f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
469f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (method != null)
470f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
471f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    buf.append ("::");
472f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    buf.append (method);
473f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
474f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
475f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                buf.append ("] ");
476f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
477f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
478f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final PrintWriter out = m_out;
479f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
480f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (msg != null) buf.append (msg);
481f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
482f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.println (buf);
483f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (FLUSH_LOG) out.flush ();
484f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
485f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
486f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
487f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private void _log (final int level, final String method,
488f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                       final String msg, final Throwable throwable)
489f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
490f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((level <= m_level) && (level >= SEVERE))
491f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
492f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final Class caller = ClassLoaderResolver.getCallerClass (2);
493f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final StringBuffer buf = new StringBuffer (m_prefix != null ? m_prefix + ": " : "");
494f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
495f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ((caller != null) || (method != null))
496f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
497f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                buf.append ("[");
498f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
499f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (caller != null) // if the caller could not be determined, s_classMask is ignored
500f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
501f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    String callerName = caller.getName ();
502f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
503f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (callerName.startsWith (PREFIX_TO_STRIP))
504f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        callerName = callerName.substring (PREFIX_TO_STRIP_LENGTH);
505f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
506f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    String parentName = callerName;
507f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
508f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final int firstDollar = callerName.indexOf ('$');
509f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (firstDollar > 0) parentName = callerName.substring (0, firstDollar);
510f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
511f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if ((m_classMask == null) || m_classMask.contains (parentName))
512f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        buf.append (callerName);
513f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else
514f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        return;
515f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
516f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
517f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (method != null)
518f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
519f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    buf.append ("::");
520f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    buf.append (method);
521f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
522f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
523f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                buf.append ("] ");
524f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
525f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
526f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final PrintWriter out = m_out;
527f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
528f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (msg != null) buf.append (msg);
529f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
530f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (throwable != null)
531f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
532f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final StringWriter sw = new StringWriter ();
533f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final PrintWriter pw = new PrintWriter (sw);
534f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
535f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throwable.printStackTrace (pw);
536f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                pw.flush ();
537f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
538f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                buf.append (sw.toString ());
539f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
540f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
541f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.println (buf);
542f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (FLUSH_LOG) out.flush ();
543f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
544f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
545f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
546f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
547f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
548f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private final int m_level; // always in [NONE, ALL] range
549f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private final PrintWriter m_out; // never null
550f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private final String m_prefix; // null is equivalent to no prefix
551f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private final Set /* String */ m_classMask; // null is equivalent to no class filtering
552f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
553f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final String PREFIX_TO_STRIP = "com.vladium."; // TODO: can this be set programmatically ?
554f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int PREFIX_TO_STRIP_LENGTH = PREFIX_TO_STRIP.length ();
555f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final boolean FLUSH_LOG = true;
556f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final String COMMA_DELIMITERS    = "," + Strings.WHITE_SPACE;
557f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
558f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final Logger STATIC_LOGGER; // set in <clinit>
559f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final ThreadLocalStack THREAD_LOCAL_STACK; // set in <clinit>
560f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
561f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    static
562f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
563f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        THREAD_LOCAL_STACK = new ThreadLocalStack ();
564f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
565f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: unfortunately, this init code makes Logger coupled to the app classes
566f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // (via the app namespace string constants)
567f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // I don't quite see an elegant solution to this design problem yet
568f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
569f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Properties properties = Property.getAppProperties (IAppConstants.APP_NAME_LC, Logger.class.getClassLoader ());
570f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
571f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // verbosity level:
572f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
573f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final int level;
574f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
575f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final String _level = properties.getProperty (AppLoggers.PROPERTY_VERBOSITY_LEVEL,
576f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                          AppLoggers.DEFAULT_VERBOSITY_LEVEL);
577f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            level = stringToLevel (_level);
578f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
579f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
580f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // verbosity filter:
581f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
582f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Set filter;
583f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
584f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final String _filter = properties.getProperty (AppLoggers.PROPERTY_VERBOSITY_FILTER);
585f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            Set temp = null;
586f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
587f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (_filter != null)
588f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
589f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final StringTokenizer tokenizer = new StringTokenizer (_filter, COMMA_DELIMITERS);
590f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (tokenizer.countTokens () > 0)
591f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
592f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    temp = new HashSet (tokenizer.countTokens ());
593f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    while (tokenizer.hasMoreTokens ())
594f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
595f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        temp.add (tokenizer.nextToken ());
596f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
597f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
598f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
599f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
600f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            filter = temp;
601f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
602f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
603f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
604f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        STATIC_LOGGER = create (level,
605f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                new PrintWriter (System.out, false),
606f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                IAppConstants.APP_NAME,
607f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                filter);
608f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
609f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
610f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project} // end of class
611f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------