#region Apache License
|
//
|
// Licensed to the Apache Software Foundation (ASF) under one or more
|
// contributor license agreements. See the NOTICE file distributed with
|
// this work for additional information regarding copyright ownership.
|
// The ASF licenses this file to you 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.
|
//
|
#endregion
|
|
using System;
|
using System.Collections;
|
using System.Diagnostics;
|
|
using log4net.Util;
|
|
namespace log4net.Core
|
{
|
/// <summary>
|
/// The internal representation of caller location information.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// This class uses the <c>System.Diagnostics.StackTrace</c> class to generate
|
/// a call stack. The caller's information is then extracted from this stack.
|
/// </para>
|
/// <para>
|
/// The <c>System.Diagnostics.StackTrace</c> class is not supported on the
|
/// .NET Compact Framework 1.0 therefore caller location information is not
|
/// available on that framework.
|
/// </para>
|
/// <para>
|
/// The <c>System.Diagnostics.StackTrace</c> class has this to say about Release builds:
|
/// </para>
|
/// <para>
|
/// "StackTrace information will be most informative with Debug build configurations.
|
/// By default, Debug builds include debug symbols, while Release builds do not. The
|
/// debug symbols contain most of the file, method name, line number, and column
|
/// information used in constructing StackFrame and StackTrace objects. StackTrace
|
/// might not report as many method calls as expected, due to code transformations
|
/// that occur during optimization."
|
/// </para>
|
/// <para>
|
/// This means that in a Release build the caller information may be incomplete or may
|
/// not exist at all! Therefore caller location information cannot be relied upon in a Release build.
|
/// </para>
|
/// </remarks>
|
/// <author>Nicko Cadell</author>
|
/// <author>Gert Driesen</author>
|
#if !NETCF
|
[Serializable]
|
#endif
|
public class LocationInfo
|
{
|
#region Public Instance Constructors
|
|
/// <summary>
|
/// Constructor
|
/// </summary>
|
/// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
|
/// the stack boundary into the logging system for this call.</param>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="LocationInfo" />
|
/// class based on the current thread.
|
/// </para>
|
/// </remarks>
|
public LocationInfo(Type callerStackBoundaryDeclaringType)
|
{
|
// Initialize all fields
|
m_className = NA;
|
m_fileName = NA;
|
m_lineNumber = NA;
|
m_methodName = NA;
|
m_fullInfo = NA;
|
|
#if !NETCF
|
if (callerStackBoundaryDeclaringType != null)
|
{
|
try
|
{
|
StackTrace st = new StackTrace(true);
|
int frameIndex = 0;
|
|
// skip frames not from fqnOfCallingClass
|
while (frameIndex < st.FrameCount)
|
{
|
StackFrame frame = st.GetFrame(frameIndex);
|
if (frame != null && frame.GetMethod().DeclaringType == callerStackBoundaryDeclaringType)
|
{
|
break;
|
}
|
frameIndex++;
|
}
|
|
// skip frames from fqnOfCallingClass
|
while (frameIndex < st.FrameCount)
|
{
|
StackFrame frame = st.GetFrame(frameIndex);
|
if (frame != null && frame.GetMethod().DeclaringType != callerStackBoundaryDeclaringType)
|
{
|
break;
|
}
|
frameIndex++;
|
}
|
|
if (frameIndex < st.FrameCount)
|
{
|
// take into account the frames we skip above
|
int adjustedFrameCount = st.FrameCount - frameIndex;
|
ArrayList stackFramesList = new ArrayList(adjustedFrameCount);
|
m_stackFrames = new StackFrame[adjustedFrameCount];
|
for (int i=frameIndex; i < st.FrameCount; i++)
|
{
|
stackFramesList.Add(st.GetFrame(i));
|
}
|
|
stackFramesList.CopyTo(m_stackFrames, 0);
|
|
// now frameIndex is the first 'user' caller frame
|
StackFrame locationFrame = st.GetFrame(frameIndex);
|
|
if (locationFrame != null)
|
{
|
System.Reflection.MethodBase method = locationFrame.GetMethod();
|
|
if (method != null)
|
{
|
m_methodName = method.Name;
|
if (method.DeclaringType != null)
|
{
|
m_className = method.DeclaringType.FullName;
|
}
|
}
|
m_fileName = locationFrame.GetFileName();
|
m_lineNumber = locationFrame.GetFileLineNumber().ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
|
|
// Combine all location info
|
m_fullInfo = m_className + '.' + m_methodName + '(' + m_fileName + ':' + m_lineNumber + ')';
|
}
|
}
|
}
|
catch(System.Security.SecurityException)
|
{
|
// This security exception will occur if the caller does not have
|
// some undefined set of SecurityPermission flags.
|
LogLog.Debug(declaringType, "Security exception while trying to get caller stack frame. Error Ignored. Location Information Not Available.");
|
}
|
}
|
#endif
|
}
|
|
/// <summary>
|
/// Constructor
|
/// </summary>
|
/// <param name="className">The fully qualified class name.</param>
|
/// <param name="methodName">The method name.</param>
|
/// <param name="fileName">The file name.</param>
|
/// <param name="lineNumber">The line number of the method within the file.</param>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="LocationInfo" />
|
/// class with the specified data.
|
/// </para>
|
/// </remarks>
|
public LocationInfo(string className, string methodName, string fileName, string lineNumber)
|
{
|
m_className = className;
|
m_fileName = fileName;
|
m_lineNumber = lineNumber;
|
m_methodName = methodName;
|
m_fullInfo = m_className + '.' + m_methodName + '(' + m_fileName +
|
':' + m_lineNumber + ')';
|
}
|
|
#endregion Public Instance Constructors
|
|
#region Public Instance Properties
|
|
/// <summary>
|
/// Gets the fully qualified class name of the caller making the logging
|
/// request.
|
/// </summary>
|
/// <value>
|
/// The fully qualified class name of the caller making the logging
|
/// request.
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets the fully qualified class name of the caller making the logging
|
/// request.
|
/// </para>
|
/// </remarks>
|
public string ClassName
|
{
|
get { return m_className; }
|
}
|
|
/// <summary>
|
/// Gets the file name of the caller.
|
/// </summary>
|
/// <value>
|
/// The file name of the caller.
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets the file name of the caller.
|
/// </para>
|
/// </remarks>
|
public string FileName
|
{
|
get { return m_fileName; }
|
}
|
|
/// <summary>
|
/// Gets the line number of the caller.
|
/// </summary>
|
/// <value>
|
/// The line number of the caller.
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets the line number of the caller.
|
/// </para>
|
/// </remarks>
|
public string LineNumber
|
{
|
get { return m_lineNumber; }
|
}
|
|
/// <summary>
|
/// Gets the method name of the caller.
|
/// </summary>
|
/// <value>
|
/// The method name of the caller.
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets the method name of the caller.
|
/// </para>
|
/// </remarks>
|
public string MethodName
|
{
|
get { return m_methodName; }
|
}
|
|
/// <summary>
|
/// Gets all available caller information
|
/// </summary>
|
/// <value>
|
/// All available caller information, in the format
|
/// <c>fully.qualified.classname.of.caller.methodName(Filename:line)</c>
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets all available caller information, in the format
|
/// <c>fully.qualified.classname.of.caller.methodName(Filename:line)</c>
|
/// </para>
|
/// </remarks>
|
public string FullInfo
|
{
|
get { return m_fullInfo; }
|
}
|
|
#if !NETCF
|
/// <summary>
|
/// Gets the stack frames from the stack trace of the caller making the log request
|
/// </summary>
|
public StackFrame[] StackFrames
|
{
|
get { return m_stackFrames; }
|
}
|
#endif
|
|
#endregion Public Instance Properties
|
|
#region Private Instance Fields
|
|
private readonly string m_className;
|
private readonly string m_fileName;
|
private readonly string m_lineNumber;
|
private readonly string m_methodName;
|
private readonly string m_fullInfo;
|
#if !NETCF
|
private readonly StackFrame[] m_stackFrames;
|
#endif
|
|
#endregion Private Instance Fields
|
|
#region Private Static Fields
|
|
/// <summary>
|
/// The fully qualified type of the LocationInfo class.
|
/// </summary>
|
/// <remarks>
|
/// Used by the internal logger to record the Type of the
|
/// log message.
|
/// </remarks>
|
private readonly static Type declaringType = typeof(LocationInfo);
|
|
/// <summary>
|
/// When location information is not available the constant
|
/// <c>NA</c> is returned. Current value of this string
|
/// constant is <b>?</b>.
|
/// </summary>
|
private const string NA = "?";
|
|
#endregion Private Static Fields
|
}
|
}
|