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
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
#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.IO;
 
using log4net.Util;
using log4net.Util.PatternStringConverters;
using log4net.Core;
 
namespace log4net.Util
{
    /// <summary>
    /// This class implements a patterned string.
    /// </summary>
    /// <remarks>
    /// <para>
    /// This string has embedded patterns that are resolved and expanded
    /// when the string is formatted.
    /// </para>
    /// <para>
    /// This class functions similarly to the <see cref="log4net.Layout.PatternLayout"/>
    /// in that it accepts a pattern and renders it to a string. Unlike the 
    /// <see cref="log4net.Layout.PatternLayout"/> however the <c>PatternString</c>
    /// does not render the properties of a specific <see cref="LoggingEvent"/> but
    /// of the process in general.
    /// </para>
    /// <para>
    /// The recognized conversion pattern names are:
    /// </para>
    /// <list type="table">
    ///     <listheader>
    ///         <term>Conversion Pattern Name</term>
    ///         <description>Effect</description>
    ///     </listheader>
    ///     <item>
    ///         <term>appdomain</term>
    ///         <description>
    ///             <para>
    ///             Used to output the friendly name of the current AppDomain.
    ///             </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>date</term>
    ///         <description>
    ///             <para>
    ///             Used to output the current date and time in the local time zone. 
    ///             To output the date in universal time use the <c>%utcdate</c> pattern.
    ///             The date conversion 
    ///             specifier may be followed by a <i>date format specifier</i> enclosed 
    ///             between braces. For example, <b>%date{HH:mm:ss,fff}</b> or
    ///             <b>%date{dd MMM yyyy HH:mm:ss,fff}</b>.  If no date format specifier is 
    ///             given then ISO8601 format is
    ///             assumed (<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>).
    ///             </para>
    ///             <para>
    ///             The date format specifier admits the same syntax as the
    ///             time pattern string of the <see cref="DateTime.ToString(string)"/>.
    ///             </para>
    ///             <para>
    ///             For better results it is recommended to use the log4net date
    ///             formatters. These can be specified using one of the strings
    ///             "ABSOLUTE", "DATE" and "ISO8601" for specifying 
    ///             <see cref="log4net.DateFormatter.AbsoluteTimeDateFormatter"/>, 
    ///             <see cref="log4net.DateFormatter.DateTimeDateFormatter"/> and respectively 
    ///             <see cref="log4net.DateFormatter.Iso8601DateFormatter"/>. For example, 
    ///             <b>%date{ISO8601}</b> or <b>%date{ABSOLUTE}</b>.
    ///             </para>
    ///             <para>
    ///             These dedicated date formatters perform significantly
    ///             better than <see cref="DateTime.ToString(string)"/>.
    ///             </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>env</term>
    ///         <description>
    ///             <para>
    ///             Used to output the a specific environment variable. The key to 
    ///             lookup must be specified within braces and directly following the
    ///             pattern specifier, e.g. <b>%env{COMPUTERNAME}</b> would include the value
    ///             of the <c>COMPUTERNAME</c> environment variable.
    ///             </para>
    ///             <para>
    ///             The <c>env</c> pattern is not supported on the .NET Compact Framework.
    ///             </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>identity</term>
    ///         <description>
    ///                <para>
    ///                Used to output the user name for the currently active user
    ///                (Principal.Identity.Name).
    ///                </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>newline</term>
    ///         <description>
    ///             <para>
    ///             Outputs the platform dependent line separator character or
    ///             characters.
    ///             </para>
    ///             <para>
    ///             This conversion pattern name offers the same performance as using 
    ///             non-portable line separator strings such as    "\n", or "\r\n". 
    ///             Thus, it is the preferred way of specifying a line separator.
    ///             </para> 
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>processid</term>
    ///         <description>
    ///             <para>
    ///                Used to output the system process ID for the current process.
    ///             </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>property</term>
    ///         <description>
    ///             <para>
    ///             Used to output a specific context property. The key to 
    ///             lookup must be specified within braces and directly following the
    ///             pattern specifier, e.g. <b>%property{user}</b> would include the value
    ///             from the property that is keyed by the string 'user'. Each property value
    ///             that is to be included in the log must be specified separately.
    ///             Properties are stored in logging contexts. By default 
    ///             the <c>log4net:HostName</c> property is set to the name of machine on 
    ///             which the event was originally logged.
    ///             </para>
    ///             <para>
    ///             If no key is specified, e.g. <b>%property</b> then all the keys and their
    ///             values are printed in a comma separated list.
    ///             </para>
    ///             <para>
    ///             The properties of an event are combined from a number of different
    ///             contexts. These are listed below in the order in which they are searched.
    ///             </para>
    ///             <list type="definition">
    ///                 <item>
    ///                     <term>the thread properties</term>
    ///                     <description>
    ///                     The <see cref="ThreadContext.Properties"/> that are set on the current
    ///                     thread. These properties are shared by all events logged on this thread.
    ///                     </description>
    ///                 </item>
    ///                 <item>
    ///                     <term>the global properties</term>
    ///                     <description>
    ///                     The <see cref="GlobalContext.Properties"/> that are set globally. These 
    ///                     properties are shared by all the threads in the AppDomain.
    ///                     </description>
    ///                 </item>
    ///             </list>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>random</term>
    ///         <description>
    ///             <para>
    ///             Used to output a random string of characters. The string is made up of
    ///             uppercase letters and numbers. By default the string is 4 characters long.
    ///             The length of the string can be specified within braces directly following the
    ///             pattern specifier, e.g. <b>%random{8}</b> would output an 8 character string.
    ///             </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>username</term>
    ///         <description>
    ///                <para>
    ///                Used to output the WindowsIdentity for the currently
    ///                active user.
    ///                </para>
    ///         </description>
    ///     </item>
    ///     <item>
    ///         <term>utcdate</term>
    ///         <description>
    ///             <para>
    ///             Used to output the date of the logging event in universal time. 
    ///             The date conversion 
    ///             specifier may be followed by a <i>date format specifier</i> enclosed 
    ///             between braces. For example, <b>%utcdate{HH:mm:ss,fff}</b> or
    ///             <b>%utcdate{dd MMM yyyy HH:mm:ss,fff}</b>.  If no date format specifier is 
    ///             given then ISO8601 format is
    ///             assumed (<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>).
    ///             </para>
    ///             <para>
    ///             The date format specifier admits the same syntax as the
    ///             time pattern string of the <see cref="DateTime.ToString(string)"/>.
    ///             </para>
    ///             <para>
    ///             For better results it is recommended to use the log4net date
    ///             formatters. These can be specified using one of the strings
    ///             "ABSOLUTE", "DATE" and "ISO8601" for specifying 
    ///             <see cref="log4net.DateFormatter.AbsoluteTimeDateFormatter"/>, 
    ///             <see cref="log4net.DateFormatter.DateTimeDateFormatter"/> and respectively 
    ///             <see cref="log4net.DateFormatter.Iso8601DateFormatter"/>. For example, 
    ///             <b>%utcdate{ISO8601}</b> or <b>%utcdate{ABSOLUTE}</b>.
    ///             </para>
    ///             <para>
    ///             These dedicated date formatters perform significantly
    ///             better than <see cref="DateTime.ToString(string)"/>.
    ///             </para>
    ///         </description>
    ///     </item>
    ///        <item>
    ///            <term>%</term>
    ///            <description>
    ///             <para>
    ///             The sequence %% outputs a single percent sign.
    ///             </para>
    ///            </description>
    ///        </item>
    /// </list>
    /// <para>
    /// Additional pattern converters may be registered with a specific <see cref="PatternString"/>
    /// instance using <see cref="AddConverter(ConverterInfo)"/> or
    /// <see cref="AddConverter(string, Type)" />.
    /// </para>
    /// <para>
    /// See the <see cref="log4net.Layout.PatternLayout"/> for details on the 
    /// <i>format modifiers</i> supported by the patterns.
    /// </para>
    /// </remarks>
    /// <author>Nicko Cadell</author>
    public class PatternString : IOptionHandler
    {
        #region Static Fields
 
        /// <summary>
        /// Internal map of converter identifiers to converter types.
        /// </summary>
        private static Hashtable s_globalRulesRegistry;
 
        #endregion Static Fields
 
        #region Member Variables
    
        /// <summary>
        /// the pattern
        /// </summary>
        private string m_pattern;
  
        /// <summary>
        /// the head of the pattern converter chain
        /// </summary>
        private PatternConverter m_head;
 
        /// <summary>
        /// patterns defined on this PatternString only
        /// </summary>
        private Hashtable m_instanceRulesRegistry = new Hashtable();
 
        #endregion
 
        #region Static Constructor
 
        /// <summary>
        /// Initialize the global registry
        /// </summary>
        static PatternString()
        {
            s_globalRulesRegistry = new Hashtable(15);
 
            s_globalRulesRegistry.Add("appdomain", typeof(AppDomainPatternConverter));
            s_globalRulesRegistry.Add("date", typeof(DatePatternConverter));
#if !NETCF
            s_globalRulesRegistry.Add("env", typeof(EnvironmentPatternConverter));
            s_globalRulesRegistry.Add("envFolderPath", typeof(EnvironmentFolderPathPatternConverter));
#endif
            s_globalRulesRegistry.Add("identity", typeof(IdentityPatternConverter));
            s_globalRulesRegistry.Add("literal", typeof(LiteralPatternConverter));
            s_globalRulesRegistry.Add("newline", typeof(NewLinePatternConverter));
            s_globalRulesRegistry.Add("processid", typeof(ProcessIdPatternConverter));
            s_globalRulesRegistry.Add("property", typeof(PropertyPatternConverter));
            s_globalRulesRegistry.Add("random", typeof(RandomStringPatternConverter));
            s_globalRulesRegistry.Add("username", typeof(UserNamePatternConverter));
 
            s_globalRulesRegistry.Add("utcdate", typeof(UtcDatePatternConverter));
            s_globalRulesRegistry.Add("utcDate", typeof(UtcDatePatternConverter));
            s_globalRulesRegistry.Add("UtcDate", typeof(UtcDatePatternConverter));
        }
 
        #endregion Static Constructor
 
        #region Constructors
 
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <remarks>
        /// <para>
        /// Initialize a new instance of <see cref="PatternString"/>
        /// </para>
        /// </remarks>
        public PatternString()
        {
        }
 
        /// <summary>
        /// Constructs a PatternString
        /// </summary>
        /// <param name="pattern">The pattern to use with this PatternString</param>
        /// <remarks>
        /// <para>
        /// Initialize a new instance of <see cref="PatternString"/> with the pattern specified.
        /// </para>
        /// </remarks>
        public PatternString(string pattern)
        {
            m_pattern = pattern;
            ActivateOptions();
        }
 
        #endregion
  
        /// <summary>
        /// Gets or sets the pattern formatting string
        /// </summary>
        /// <value>
        /// The pattern formatting string
        /// </value>
        /// <remarks>
        /// <para>
        /// The <b>ConversionPattern</b> option. This is the string which
        /// controls formatting and consists of a mix of literal content and
        /// conversion specifiers.
        /// </para>
        /// </remarks>
        public string ConversionPattern
        {
            get { return m_pattern;    }
            set { m_pattern = value; }
        }
 
        #region Implementation of IOptionHandler
 
        /// <summary>
        /// Initialize object options
        /// </summary>
        /// <remarks>
        /// <para>
        /// This is part of the <see cref="IOptionHandler"/> delayed object
        /// activation scheme. The <see cref="ActivateOptions"/> method must 
        /// be called on this object after the configuration properties have
        /// been set. Until <see cref="ActivateOptions"/> is called this
        /// object is in an undefined state and must not be used. 
        /// </para>
        /// <para>
        /// If any of the configuration properties are modified then 
        /// <see cref="ActivateOptions"/> must be called again.
        /// </para>
        /// </remarks>
        virtual public void ActivateOptions() 
        {
            m_head = CreatePatternParser(m_pattern).Parse();
        }
 
        #endregion
 
        /// <summary>
        /// Create the <see cref="PatternParser"/> used to parse the pattern
        /// </summary>
        /// <param name="pattern">the pattern to parse</param>
        /// <returns>The <see cref="PatternParser"/></returns>
        /// <remarks>
        /// <para>
        /// Returns PatternParser used to parse the conversion string. Subclasses
        /// may override this to return a subclass of PatternParser which recognize
        /// custom conversion pattern name.
        /// </para>
        /// </remarks>
        private PatternParser CreatePatternParser(string pattern) 
        {
            PatternParser patternParser = new PatternParser(pattern);
 
            // Add all the builtin patterns
            foreach(DictionaryEntry entry in s_globalRulesRegistry)
            {
                ConverterInfo converterInfo = new ConverterInfo();
                converterInfo.Name = (string)entry.Key;
                converterInfo.Type = (Type)entry.Value;
                patternParser.PatternConverters.Add(entry.Key, converterInfo);
            }
            // Add the instance patterns
            foreach(DictionaryEntry entry in m_instanceRulesRegistry)
            {
                patternParser.PatternConverters[entry.Key] = entry.Value;
            }
 
            return patternParser;
        }
  
        /// <summary>
        /// Produces a formatted string as specified by the conversion pattern.
        /// </summary>
        /// <param name="writer">The TextWriter to write the formatted event to</param>
        /// <remarks>
        /// <para>
        /// Format the pattern to the <paramref name="writer"/>.
        /// </para>
        /// </remarks>
        public void Format(TextWriter writer) 
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
 
            PatternConverter c = m_head;
 
            // loop through the chain of pattern converters
            while(c != null) 
            {
                c.Format(writer, null);
                c = c.Next;
            }
        }
 
        /// <summary>
        /// Format the pattern as a string
        /// </summary>
        /// <returns>the pattern formatted as a string</returns>
        /// <remarks>
        /// <para>
        /// Format the pattern to a string.
        /// </para>
        /// </remarks>
        public string Format() 
        {
            StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
            Format(writer);
            return writer.ToString();
        }
 
        /// <summary>
        /// Add a converter to this PatternString
        /// </summary>
        /// <param name="converterInfo">the converter info</param>
        /// <remarks>
        /// <para>
        /// This version of the method is used by the configurator.
        /// Programmatic users should use the alternative <see cref="AddConverter(string,Type)"/> method.
        /// </para>
        /// </remarks>
        public void AddConverter(ConverterInfo converterInfo)
        {
            if (converterInfo == null) throw new ArgumentNullException("converterInfo");
 
            if (!typeof(PatternConverter).IsAssignableFrom(converterInfo.Type))
            {
                throw new ArgumentException("The converter type specified [" + converterInfo.Type + "] must be a subclass of log4net.Util.PatternConverter", "converterInfo");
            }
            m_instanceRulesRegistry[converterInfo.Name] = converterInfo;
        }
 
        /// <summary>
        /// Add a converter to this PatternString
        /// </summary>
        /// <param name="name">the name of the conversion pattern for this converter</param>
        /// <param name="type">the type of the converter</param>
        /// <remarks>
        /// <para>
        /// Add a converter to this PatternString
        /// </para>
        /// </remarks>
        public void AddConverter(string name, Type type)
        {
            if (name == null) throw new ArgumentNullException("name");
            if (type == null) throw new ArgumentNullException("type");
 
            ConverterInfo converterInfo = new ConverterInfo();
            converterInfo.Name = name;
            converterInfo.Type = type;
 
            AddConverter(converterInfo);
        }
    }
}