Files
Sun1602/GameLogic/include/log4cxx/ndc.h
T
2022-10-26 12:25:11 +08:00

217 lines
7.5 KiB
C++

/*
* Copyright 2003,2004 The Apache Software Foundation.
*
* 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.
*/
#ifndef _LOG4CXX_NDC_H
#define _LOG4CXX_NDC_H
#include <log4cxx/helpers/tchar.h>
#include <log4cxx/helpers/threadspecificdata.h>
#include <stack>
namespace log4cxx
{
class DiagnosticContext;
typedef std::stack<DiagnosticContext> Stack;
/**
the ndc class implements <i>nested diagnostic contexts</i> as
defined by neil harrison in the article "patterns for logging
diagnostic messages" part of the book "<i>pattern languages of
program design 3</i>" edited by martin et al.
<p>a nested diagnostic context, or ndc in short, is an instrument
to distinguish interleaved log output from different sources. log
output is typically interleaved when a server handles multiple
clients near-simultaneously.
<p>interleaved log output can still be meaningful if each log entry
from different contexts had a distinctive stamp. this is where ndcs
come into play.
<p><em><b>note that ndcs are managed on a per thread
basis</b></em>. ndc operations such as #push,
#pop, #clear and #getDepth
affect the ndc of the <em>current</em> thread only. ndcs of other
threads remain unaffected.
<p>for example, a servlet can build a per client request ndc
consisting the clients host name and other information contained in
the the request. <em>cookies</em> are another source of distinctive
information. to build an ndc one uses the #push
operation. simply put,
<p><ul>
<li>contexts can be nested.
<p><li>when entering a context, call <code>ndc.push</code>. as a
side effect, if there is no nested diagnostic context for the
current thread, this method will create it.
<p><li>when leaving a context, call <code>ndc.pop</code>.
<p><li><b>when exiting a thread make sure to call #remove
</b>.
</ul>
<p>there is no penalty for forgetting to match each
<code>push</code> operation with a corresponding <code>pop</code>,
except the obvious mismatch between the real application context
and the context set in the ndc.
<p>if configured to do so, PatternLayout and
TTCCLayout instances automatically retrieve the nested diagnostic
context for the current thread without any user intervention.
hence, even if a servlet is serving multiple clients
simultaneously, the logs emanating from the same code (belonging to
the same category) can still be distinguished because each client
request will have a different ndc tag.
<p>heavy duty systems should call the #remove method when
leaving the run method of a thread. this ensures that the memory
used by the thread can be freed by the java garbage
collector. there is a mechanism to lazily remove references to dead
threads. in practice, this means that you can be a little sloppy
and sometimes forget to call #remove before exiting a
thread.
<p>a thread may inherit the nested diagnostic context of another
(possibly parent) thread using the #inherit
method. a thread may obtain a copy of its ndc with the
#clonestack method and pass the reference to any other
thread, in particular to a child.
*/
class LOG4CXX_EXPORT NDC
{
private:
class DiagnosticContext
{
public:
String fullMessage;
String message;
DiagnosticContext(const String& message,
const DiagnosticContext * parent);
};
typedef std::stack<DiagnosticContext> Stack;
static Stack * getCurrentThreadStack();
static void setCurrentThreadStack(Stack * stack);
static helpers::ThreadSpecificData threadSpecificData;
public:
NDC(const String& message);
~NDC();
/**
Clear any nested diagnostic information if any. This method is
useful in cases where the same thread can be potentially used
over and over in different unrelated contexts.
<p>This method is equivalent to calling the #setMaxDepth
method with a zero <code>maxDepth</code> argument.
*/
static void clear();
/**
Clone the diagnostic context for the current thread.
<p>Internally a diagnostic context is represented as a stack. A
given thread can supply the stack (i.e. diagnostic context) to a
child thread so that the child can inherit the parent thread's
diagnostic context.
<p>The child thread uses the #inherit method to
inherit the parent's diagnostic context.
@return Stack A clone of the current thread's diagnostic context.
*/
static Stack * cloneStack();
/**
Inherit the diagnostic context of another thread.
<p>The parent thread can obtain a reference to its diagnostic
context using the #cloneStack method. It should
communicate this information to its child so that it may inherit
the parent's diagnostic context.
<p>The parent's diagnostic context is cloned before being
inherited. In other words, once inherited, the two diagnostic
contexts can be managed independently.
<p>In java, a child thread cannot obtain a reference to its
parent, unless it is directly handed the reference. Consequently,
there is no client-transparent way of inheriting diagnostic
contexts. Do you know any solution to this problem?
@param stack The diagnostic context of the parent thread.
*/
static void inherit(Stack * stack);
/**
<b>Never use this method directly, use the
{@link spi::LoggingEvent#getNDC LoggingEvent::getNDC}
method instead.</b>
*/
static String get();
/**
Get the current nesting depth of this diagnostic context.
*/
static int getDepth();
/**
Clients should call this method before leaving a diagnostic
context.
<p>The returned value is the value that was pushed last. If no
context is available, then the empty string "" is returned.
@return String The innermost diagnostic context.
*/
static String pop();
/**
Looks at the last diagnostic context at the top of this NDC
without removing it.
<p>The returned value is the value that was pushed last. If no
context is available, then the empty string "" is returned.
@return String The innermost diagnostic context.
*/
static String peek();
/**
Push new diagnostic context information for the current thread.
<p>The contents of the <code>message</code> parameter is
determined solely by the client.
@param message The new diagnostic context information.
*/
static void push(const String& message);
/**
Remove the diagnostic context for this thread.
<p>Each thread that created a diagnostic context by calling
#push should call this method before exiting. Otherwise,
the memory used by the <b>thread</b> cannot be reclaimed by the
VM.
<p>As this is such an important problem in heavy duty systems and
because it is difficult to always guarantee that the remove
method is called before exiting a thread, this method has been
augmented to lazily remove references to dead threads. In
practice, this means that you can be a little sloppy and
occasionally forget to call #remove before exiting a
thread. However, you must call <code>remove</code> sometime. If
you never call it, then your application is sure to run out of
memory.
*/
static void remove();
}; // class NDC;
} // namespace log4cxx
#endif // _LOG4CXX_NDC_H