jt
2021-06-10 5d0d028456874576560552f5a5c4e8b801786f11
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#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
    }
}