LoggingEvent.cs 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. #region Apache License
  2. //
  3. // Licensed to the Apache Software Foundation (ASF) under one or more
  4. // contributor license agreements. See the NOTICE file distributed with
  5. // this work for additional information regarding copyright ownership.
  6. // The ASF licenses this file to you under the Apache License, Version 2.0
  7. // (the "License"); you may not use this file except in compliance with
  8. // the License. You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. using System;
  20. using System.Collections;
  21. using System.IO;
  22. #if (!NETCF)
  23. using System.Runtime.Serialization;
  24. #if !NETSTANDARD1_3
  25. using System.Security.Principal;
  26. #endif
  27. #endif
  28. using log4net.Util;
  29. using log4net.Repository;
  30. namespace log4net.Core
  31. {
  32. /// <summary>
  33. /// Portable data structure used by <see cref="LoggingEvent"/>
  34. /// </summary>
  35. /// <remarks>
  36. /// <para>
  37. /// Portable data structure used by <see cref="LoggingEvent"/>
  38. /// </para>
  39. /// </remarks>
  40. /// <author>Nicko Cadell</author>
  41. public struct LoggingEventData
  42. {
  43. #region Public Instance Fields
  44. /// <summary>
  45. /// The logger name.
  46. /// </summary>
  47. /// <remarks>
  48. /// <para>
  49. /// The logger name.
  50. /// </para>
  51. /// </remarks>
  52. public string LoggerName;
  53. /// <summary>
  54. /// Level of logging event.
  55. /// </summary>
  56. /// <remarks>
  57. /// <para>
  58. /// Level of logging event. Level cannot be Serializable
  59. /// because it is a flyweight. Due to its special serialization it
  60. /// cannot be declared final either.
  61. /// </para>
  62. /// </remarks>
  63. public Level Level;
  64. /// <summary>
  65. /// The application supplied message.
  66. /// </summary>
  67. /// <remarks>
  68. /// <para>
  69. /// The application supplied message of logging event.
  70. /// </para>
  71. /// </remarks>
  72. public string Message;
  73. /// <summary>
  74. /// The name of thread
  75. /// </summary>
  76. /// <remarks>
  77. /// <para>
  78. /// The name of thread in which this logging event was generated
  79. /// </para>
  80. /// </remarks>
  81. public string ThreadName;
  82. /// <summary>
  83. /// Gets or sets the local time the event was logged
  84. /// </summary>
  85. /// <remarks>
  86. /// <para>
  87. /// Prefer using the <see cref="TimeStampUtc"/> setter, since local time can be ambiguous.
  88. /// </para>
  89. /// </remarks>
  90. [Obsolete("Prefer using TimeStampUtc, since local time can be ambiguous in time zones with daylight savings time.")]
  91. public DateTime TimeStamp;
  92. /// <summary>
  93. /// Gets or sets the UTC time the event was logged
  94. /// </summary>
  95. /// <remarks>
  96. /// <para>
  97. /// The TimeStamp is stored in the UTC time zone.
  98. /// </para>
  99. /// </remarks>
  100. #pragma warning disable 618 // Suppress warnings that TimeStamp field is obsolete
  101. public DateTime TimeStampUtc
  102. {
  103. get
  104. {
  105. if (TimeStamp != default(DateTime) &&
  106. _timeStampUtc == default(DateTime))
  107. {
  108. // TimeStamp field has been set explicitly but TimeStampUtc hasn't
  109. // => use TimeStamp
  110. return TimeStamp.ToUniversalTime();
  111. }
  112. return _timeStampUtc;
  113. }
  114. set
  115. {
  116. _timeStampUtc = value;
  117. // For backwards compatibility
  118. TimeStamp = _timeStampUtc.ToLocalTime();
  119. }
  120. }
  121. private DateTime _timeStampUtc;
  122. #pragma warning restore 618
  123. /// <summary>
  124. /// Location information for the caller.
  125. /// </summary>
  126. /// <remarks>
  127. /// <para>
  128. /// Location information for the caller.
  129. /// </para>
  130. /// </remarks>
  131. public LocationInfo LocationInfo;
  132. /// <summary>
  133. /// String representation of the user
  134. /// </summary>
  135. /// <remarks>
  136. /// <para>
  137. /// String representation of the user's windows name,
  138. /// like DOMAIN\username
  139. /// </para>
  140. /// </remarks>
  141. public string UserName;
  142. /// <summary>
  143. /// String representation of the identity.
  144. /// </summary>
  145. /// <remarks>
  146. /// <para>
  147. /// String representation of the current thread's principal identity.
  148. /// </para>
  149. /// </remarks>
  150. public string Identity;
  151. /// <summary>
  152. /// The string representation of the exception
  153. /// </summary>
  154. /// <remarks>
  155. /// <para>
  156. /// The string representation of the exception
  157. /// </para>
  158. /// </remarks>
  159. public string ExceptionString;
  160. /// <summary>
  161. /// String representation of the AppDomain.
  162. /// </summary>
  163. /// <remarks>
  164. /// <para>
  165. /// String representation of the AppDomain.
  166. /// </para>
  167. /// </remarks>
  168. public string Domain;
  169. /// <summary>
  170. /// Additional event specific properties
  171. /// </summary>
  172. /// <remarks>
  173. /// <para>
  174. /// A logger or an appender may attach additional
  175. /// properties to specific events. These properties
  176. /// have a string key and an object value.
  177. /// </para>
  178. /// </remarks>
  179. public PropertiesDictionary Properties;
  180. #endregion Public Instance Fields
  181. }
  182. /// <summary>
  183. /// Flags passed to the <see cref="LoggingEvent.Fix"/> property
  184. /// </summary>
  185. /// <remarks>
  186. /// <para>
  187. /// Flags passed to the <see cref="LoggingEvent.Fix"/> property
  188. /// </para>
  189. /// </remarks>
  190. /// <author>Nicko Cadell</author>
  191. [Flags] public enum FixFlags
  192. {
  193. /// <summary>
  194. /// Fix the MDC
  195. /// </summary>
  196. [Obsolete("Replaced by composite Properties")]
  197. Mdc = 0x01,
  198. /// <summary>
  199. /// Fix the NDC
  200. /// </summary>
  201. Ndc = 0x02,
  202. /// <summary>
  203. /// Fix the rendered message
  204. /// </summary>
  205. Message = 0x04,
  206. /// <summary>
  207. /// Fix the thread name
  208. /// </summary>
  209. ThreadName = 0x08,
  210. /// <summary>
  211. /// Fix the callers location information
  212. /// </summary>
  213. /// <remarks>
  214. /// CAUTION: Very slow to generate
  215. /// </remarks>
  216. LocationInfo = 0x10,
  217. /// <summary>
  218. /// Fix the callers windows user name
  219. /// </summary>
  220. /// <remarks>
  221. /// CAUTION: Slow to generate
  222. /// </remarks>
  223. UserName = 0x20,
  224. /// <summary>
  225. /// Fix the domain friendly name
  226. /// </summary>
  227. Domain = 0x40,
  228. /// <summary>
  229. /// Fix the callers principal name
  230. /// </summary>
  231. /// <remarks>
  232. /// CAUTION: May be slow to generate
  233. /// </remarks>
  234. Identity = 0x80,
  235. /// <summary>
  236. /// Fix the exception text
  237. /// </summary>
  238. Exception = 0x100,
  239. /// <summary>
  240. /// Fix the event properties. Active properties must implement <see cref="IFixingRequired"/> in order to be eligible for fixing.
  241. /// </summary>
  242. Properties = 0x200,
  243. /// <summary>
  244. /// No fields fixed
  245. /// </summary>
  246. None = 0x0,
  247. /// <summary>
  248. /// All fields fixed
  249. /// </summary>
  250. All = 0xFFFFFFF,
  251. /// <summary>
  252. /// Partial fields fixed
  253. /// </summary>
  254. /// <remarks>
  255. /// <para>
  256. /// This set of partial fields gives good performance. The following fields are fixed:
  257. /// </para>
  258. /// <list type="bullet">
  259. /// <item><description><see cref="Message"/></description></item>
  260. /// <item><description><see cref="ThreadName"/></description></item>
  261. /// <item><description><see cref="Exception"/></description></item>
  262. /// <item><description><see cref="Domain"/></description></item>
  263. /// <item><description><see cref="Properties"/></description></item>
  264. /// </list>
  265. /// </remarks>
  266. Partial = Message | ThreadName | Exception | Domain | Properties,
  267. }
  268. /// <summary>
  269. /// The internal representation of logging events.
  270. /// </summary>
  271. /// <remarks>
  272. /// <para>
  273. /// When an affirmative decision is made to log then a
  274. /// <see cref="LoggingEvent"/> instance is created. This instance
  275. /// is passed around to the different log4net components.
  276. /// </para>
  277. /// <para>
  278. /// This class is of concern to those wishing to extend log4net.
  279. /// </para>
  280. /// <para>
  281. /// Some of the values in instances of <see cref="LoggingEvent"/>
  282. /// are considered volatile, that is the values are correct at the
  283. /// time the event is delivered to appenders, but will not be consistent
  284. /// at any time afterwards. If an event is to be stored and then processed
  285. /// at a later time these volatile values must be fixed by calling
  286. /// <see cref="M:FixVolatileData()"/>. There is a performance penalty
  287. /// for incurred by calling <see cref="M:FixVolatileData()"/> but it
  288. /// is essential to maintaining data consistency.
  289. /// </para>
  290. /// </remarks>
  291. /// <author>Nicko Cadell</author>
  292. /// <author>Gert Driesen</author>
  293. /// <author>Douglas de la Torre</author>
  294. /// <author>Daniel Cazzulino</author>
  295. #if !NETCF
  296. [Serializable]
  297. #endif
  298. public class LoggingEvent
  299. #if !NETCF
  300. : ISerializable
  301. #endif
  302. {
  303. private readonly static Type declaringType = typeof(LoggingEvent);
  304. #region Public Instance Constructors
  305. /// <summary>
  306. /// Initializes a new instance of the <see cref="LoggingEvent" /> class
  307. /// from the supplied parameters.
  308. /// </summary>
  309. /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
  310. /// the stack boundary into the logging system for this call.</param>
  311. /// <param name="repository">The repository this event is logged in.</param>
  312. /// <param name="loggerName">The name of the logger of this event.</param>
  313. /// <param name="level">The level of this event.</param>
  314. /// <param name="message">The message of this event.</param>
  315. /// <param name="exception">The exception for this event.</param>
  316. /// <remarks>
  317. /// <para>
  318. /// Except <see cref="TimeStamp"/>, <see cref="Level"/> and <see cref="LoggerName"/>,
  319. /// all fields of <c>LoggingEvent</c> are filled when actually needed. Call
  320. /// <see cref="M:FixVolatileData()"/> to cache all data locally
  321. /// to prevent inconsistencies.
  322. /// </para>
  323. /// <para>This method is called by the log4net framework
  324. /// to create a logging event.
  325. /// </para>
  326. /// </remarks>
  327. public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, string loggerName, Level level, object message, Exception exception)
  328. {
  329. m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType;
  330. m_message = message;
  331. m_repository = repository;
  332. m_thrownException = exception;
  333. m_data.LoggerName = loggerName;
  334. m_data.Level = level;
  335. // Store the event creation time
  336. m_data.TimeStampUtc = DateTime.UtcNow;
  337. }
  338. /// <summary>
  339. /// Initializes a new instance of the <see cref="LoggingEvent" /> class
  340. /// using specific data.
  341. /// </summary>
  342. /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
  343. /// the stack boundary into the logging system for this call.</param>
  344. /// <param name="repository">The repository this event is logged in.</param>
  345. /// <param name="data">Data used to initialize the logging event.</param>
  346. /// <param name="fixedData">The fields in the <paranref name="data"/> struct that have already been fixed.</param>
  347. /// <remarks>
  348. /// <para>
  349. /// This constructor is provided to allow a <see cref="LoggingEvent" />
  350. /// to be created independently of the log4net framework. This can
  351. /// be useful if you require a custom serialization scheme.
  352. /// </para>
  353. /// <para>
  354. /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an
  355. /// instance of the <see cref="LoggingEventData"/> class.
  356. /// </para>
  357. /// <para>
  358. /// The <paramref name="fixedData"/> parameter should be used to specify which fields in the
  359. /// <paramref name="data"/> struct have been preset. Fields not specified in the <paramref name="fixedData"/>
  360. /// will be captured from the environment if requested or fixed.
  361. /// </para>
  362. /// </remarks>
  363. public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data, FixFlags fixedData)
  364. {
  365. m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType;
  366. m_repository = repository;
  367. m_data = data;
  368. m_fixFlags = fixedData;
  369. }
  370. /// <summary>
  371. /// Initializes a new instance of the <see cref="LoggingEvent" /> class
  372. /// using specific data.
  373. /// </summary>
  374. /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
  375. /// the stack boundary into the logging system for this call.</param>
  376. /// <param name="repository">The repository this event is logged in.</param>
  377. /// <param name="data">Data used to initialize the logging event.</param>
  378. /// <remarks>
  379. /// <para>
  380. /// This constructor is provided to allow a <see cref="LoggingEvent" />
  381. /// to be created independently of the log4net framework. This can
  382. /// be useful if you require a custom serialization scheme.
  383. /// </para>
  384. /// <para>
  385. /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an
  386. /// instance of the <see cref="LoggingEventData"/> class.
  387. /// </para>
  388. /// <para>
  389. /// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>,
  390. /// this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
  391. /// parameter and no other data should be captured from the environment.
  392. /// </para>
  393. /// </remarks>
  394. public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data) : this(callerStackBoundaryDeclaringType, repository, data, FixFlags.All)
  395. {
  396. }
  397. /// <summary>
  398. /// Initializes a new instance of the <see cref="LoggingEvent" /> class
  399. /// using specific data.
  400. /// </summary>
  401. /// <param name="data">Data used to initialize the logging event.</param>
  402. /// <remarks>
  403. /// <para>
  404. /// This constructor is provided to allow a <see cref="LoggingEvent" />
  405. /// to be created independently of the log4net framework. This can
  406. /// be useful if you require a custom serialization scheme.
  407. /// </para>
  408. /// <para>
  409. /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an
  410. /// instance of the <see cref="LoggingEventData"/> class.
  411. /// </para>
  412. /// <para>
  413. /// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>,
  414. /// this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
  415. /// parameter and no other data should be captured from the environment.
  416. /// </para>
  417. /// </remarks>
  418. public LoggingEvent(LoggingEventData data) : this(null, null, data)
  419. {
  420. }
  421. #endregion Public Instance Constructors
  422. #region Protected Instance Constructors
  423. #if !NETCF
  424. /// <summary>
  425. /// Serialization constructor
  426. /// </summary>
  427. /// <param name="info">The <see cref="SerializationInfo" /> that holds the serialized object data.</param>
  428. /// <param name="context">The <see cref="StreamingContext" /> that contains contextual information about the source or destination.</param>
  429. /// <remarks>
  430. /// <para>
  431. /// Initializes a new instance of the <see cref="LoggingEvent" /> class
  432. /// with serialized data.
  433. /// </para>
  434. /// </remarks>
  435. protected LoggingEvent(SerializationInfo info, StreamingContext context)
  436. {
  437. m_data.LoggerName = info.GetString("LoggerName");
  438. // Note we are deserializing the whole level object. That is the
  439. // name and the value. This value is correct for the source
  440. // hierarchy but may not be for the target hierarchy that this
  441. // event may be re-logged into. If it is to be re-logged it may
  442. // be necessary to re-lookup the level based only on the name.
  443. m_data.Level = (Level)info.GetValue("Level", typeof(Level));
  444. m_data.Message = info.GetString("Message");
  445. m_data.ThreadName = info.GetString("ThreadName");
  446. m_data.TimeStampUtc = info.GetDateTime("TimeStamp").ToUniversalTime();
  447. m_data.LocationInfo = (LocationInfo) info.GetValue("LocationInfo", typeof(LocationInfo));
  448. m_data.UserName = info.GetString("UserName");
  449. m_data.ExceptionString = info.GetString("ExceptionString");
  450. m_data.Properties = (PropertiesDictionary) info.GetValue("Properties", typeof(PropertiesDictionary));
  451. m_data.Domain = info.GetString("Domain");
  452. m_data.Identity = info.GetString("Identity");
  453. // We have restored all the values of this instance, i.e. all the values are fixed
  454. // Set the fix flags otherwise the data values may be overwritten from the current environment.
  455. m_fixFlags = FixFlags.All;
  456. }
  457. #endif
  458. #endregion Protected Instance Constructors
  459. #region Public Instance Properties
  460. /// <summary>
  461. /// Gets the time when the current process started.
  462. /// </summary>
  463. /// <value>
  464. /// This is the time when this process started.
  465. /// </value>
  466. /// <remarks>
  467. /// <para>
  468. /// The TimeStamp is stored internally in UTC and converted to the local time zone for this computer.
  469. /// </para>
  470. /// <para>
  471. /// Tries to get the start time for the current process.
  472. /// Failing that it returns the time of the first call to
  473. /// this property.
  474. /// </para>
  475. /// <para>
  476. /// Note that AppDomains may be loaded and unloaded within the
  477. /// same process without the process terminating and therefore
  478. /// without the process start time being reset.
  479. /// </para>
  480. /// </remarks>
  481. public static DateTime StartTime
  482. {
  483. get { return SystemInfo.ProcessStartTimeUtc.ToLocalTime(); }
  484. }
  485. /// <summary>
  486. /// Gets the UTC time when the current process started.
  487. /// </summary>
  488. /// <value>
  489. /// This is the UTC time when this process started.
  490. /// </value>
  491. /// <remarks>
  492. /// <para>
  493. /// Tries to get the start time for the current process.
  494. /// Failing that it returns the time of the first call to
  495. /// this property.
  496. /// </para>
  497. /// <para>
  498. /// Note that AppDomains may be loaded and unloaded within the
  499. /// same process without the process terminating and therefore
  500. /// without the process start time being reset.
  501. /// </para>
  502. /// </remarks>
  503. public static DateTime StartTimeUtc
  504. {
  505. get { return SystemInfo.ProcessStartTimeUtc; }
  506. }
  507. /// <summary>
  508. /// Gets the <see cref="Level" /> of the logging event.
  509. /// </summary>
  510. /// <value>
  511. /// The <see cref="Level" /> of the logging event.
  512. /// </value>
  513. /// <remarks>
  514. /// <para>
  515. /// Gets the <see cref="Level" /> of the logging event.
  516. /// </para>
  517. /// </remarks>
  518. public Level Level
  519. {
  520. get { return m_data.Level; }
  521. }
  522. /// <summary>
  523. /// Gets the time of the logging event.
  524. /// </summary>
  525. /// <value>
  526. /// The time of the logging event.
  527. /// </value>
  528. /// <remarks>
  529. /// <para>
  530. /// The TimeStamp is stored in UTC and converted to the local time zone for this computer.
  531. /// </para>
  532. /// </remarks>
  533. public DateTime TimeStamp
  534. {
  535. get { return m_data.TimeStampUtc.ToLocalTime(); }
  536. }
  537. /// <summary>
  538. /// Gets UTC the time of the logging event.
  539. /// </summary>
  540. /// <value>
  541. /// The UTC time of the logging event.
  542. /// </value>
  543. public DateTime TimeStampUtc
  544. {
  545. get { return m_data.TimeStampUtc; }
  546. }
  547. /// <summary>
  548. /// Gets the name of the logger that logged the event.
  549. /// </summary>
  550. /// <value>
  551. /// The name of the logger that logged the event.
  552. /// </value>
  553. /// <remarks>
  554. /// <para>
  555. /// Gets the name of the logger that logged the event.
  556. /// </para>
  557. /// </remarks>
  558. public string LoggerName
  559. {
  560. get { return m_data.LoggerName; }
  561. }
  562. /// <summary>
  563. /// Gets the location information for this logging event.
  564. /// </summary>
  565. /// <value>
  566. /// The location information for this logging event.
  567. /// </value>
  568. /// <remarks>
  569. /// <para>
  570. /// The collected information is cached for future use.
  571. /// </para>
  572. /// <para>
  573. /// See the <see cref="LocationInfo"/> class for more information on
  574. /// supported frameworks and the different behavior in Debug and
  575. /// Release builds.
  576. /// </para>
  577. /// </remarks>
  578. public LocationInfo LocationInformation
  579. {
  580. get
  581. {
  582. if (m_data.LocationInfo == null && this.m_cacheUpdatable)
  583. {
  584. m_data.LocationInfo = new LocationInfo(m_callerStackBoundaryDeclaringType);
  585. }
  586. return m_data.LocationInfo;
  587. }
  588. }
  589. /// <summary>
  590. /// Gets the message object used to initialize this event.
  591. /// </summary>
  592. /// <value>
  593. /// The message object used to initialize this event.
  594. /// </value>
  595. /// <remarks>
  596. /// <para>
  597. /// Gets the message object used to initialize this event.
  598. /// Note that this event may not have a valid message object.
  599. /// If the event is serialized the message object will not
  600. /// be transferred. To get the text of the message the
  601. /// <see cref="RenderedMessage"/> property must be used
  602. /// not this property.
  603. /// </para>
  604. /// <para>
  605. /// If there is no defined message object for this event then
  606. /// null will be returned.
  607. /// </para>
  608. /// </remarks>
  609. public object MessageObject
  610. {
  611. get { return m_message; }
  612. }
  613. /// <summary>
  614. /// Gets the exception object used to initialize this event.
  615. /// </summary>
  616. /// <value>
  617. /// The exception object used to initialize this event.
  618. /// </value>
  619. /// <remarks>
  620. /// <para>
  621. /// Gets the exception object used to initialize this event.
  622. /// Note that this event may not have a valid exception object.
  623. /// If the event is serialized the exception object will not
  624. /// be transferred. To get the text of the exception the
  625. /// <see cref="GetExceptionString"/> method must be used
  626. /// not this property.
  627. /// </para>
  628. /// <para>
  629. /// If there is no defined exception object for this event then
  630. /// null will be returned.
  631. /// </para>
  632. /// </remarks>
  633. public Exception ExceptionObject
  634. {
  635. get { return m_thrownException; }
  636. }
  637. /// <summary>
  638. /// The <see cref="ILoggerRepository"/> that this event was created in.
  639. /// </summary>
  640. /// <remarks>
  641. /// <para>
  642. /// The <see cref="ILoggerRepository"/> that this event was created in.
  643. /// </para>
  644. /// </remarks>
  645. public ILoggerRepository Repository
  646. {
  647. get { return m_repository; }
  648. }
  649. /// <summary>
  650. /// Ensure that the repository is set.
  651. /// </summary>
  652. /// <param name="repository">the value for the repository</param>
  653. internal void EnsureRepository(ILoggerRepository repository)
  654. {
  655. if (repository != null)
  656. {
  657. m_repository = repository;
  658. }
  659. }
  660. /// <summary>
  661. /// Gets the message, rendered through the <see cref="ILoggerRepository.RendererMap" />.
  662. /// </summary>
  663. /// <value>
  664. /// The message rendered through the <see cref="ILoggerRepository.RendererMap" />.
  665. /// </value>
  666. /// <remarks>
  667. /// <para>
  668. /// The collected information is cached for future use.
  669. /// </para>
  670. /// </remarks>
  671. public string RenderedMessage
  672. {
  673. get
  674. {
  675. if (m_data.Message == null && this.m_cacheUpdatable)
  676. {
  677. if (m_message == null)
  678. {
  679. m_data.Message = "";
  680. }
  681. else if (m_message is string)
  682. {
  683. m_data.Message = (m_message as string);
  684. }
  685. else if (m_repository != null)
  686. {
  687. m_data.Message = m_repository.RendererMap.FindAndRender(m_message);
  688. }
  689. else
  690. {
  691. // Very last resort
  692. m_data.Message = m_message.ToString();
  693. }
  694. }
  695. return m_data.Message;
  696. }
  697. }
  698. /// <summary>
  699. /// Write the rendered message to a TextWriter
  700. /// </summary>
  701. /// <param name="writer">the writer to write the message to</param>
  702. /// <remarks>
  703. /// <para>
  704. /// Unlike the <see cref="RenderedMessage"/> property this method
  705. /// does store the message data in the internal cache. Therefore
  706. /// if called only once this method should be faster than the
  707. /// <see cref="RenderedMessage"/> property, however if the message is
  708. /// to be accessed multiple times then the property will be more efficient.
  709. /// </para>
  710. /// </remarks>
  711. public void WriteRenderedMessage(TextWriter writer)
  712. {
  713. if (m_data.Message != null)
  714. {
  715. writer.Write(m_data.Message);
  716. }
  717. else
  718. {
  719. if (m_message != null)
  720. {
  721. if (m_message is string)
  722. {
  723. writer.Write(m_message as string);
  724. }
  725. else if (m_repository != null)
  726. {
  727. m_repository.RendererMap.FindAndRender(m_message, writer);
  728. }
  729. else
  730. {
  731. // Very last resort
  732. writer.Write(m_message.ToString());
  733. }
  734. }
  735. }
  736. }
  737. /// <summary>
  738. /// Gets the name of the current thread.
  739. /// </summary>
  740. /// <value>
  741. /// The name of the current thread, or the thread ID when
  742. /// the name is not available.
  743. /// </value>
  744. /// <remarks>
  745. /// <para>
  746. /// The collected information is cached for future use.
  747. /// </para>
  748. /// </remarks>
  749. public string ThreadName
  750. {
  751. get
  752. {
  753. if (m_data.ThreadName == null && this.m_cacheUpdatable)
  754. {
  755. #if NETCF
  756. // Get thread ID only
  757. m_data.ThreadName = SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
  758. #else
  759. m_data.ThreadName = System.Threading.Thread.CurrentThread.Name;
  760. if (m_data.ThreadName == null || m_data.ThreadName.Length == 0)
  761. {
  762. // The thread name is not available. Therefore we
  763. // go the the AppDomain to get the ID of the
  764. // current thread. (Why don't Threads know their own ID?)
  765. try
  766. {
  767. m_data.ThreadName = SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
  768. }
  769. catch(System.Security.SecurityException)
  770. {
  771. // This security exception will occur if the caller does not have
  772. // some undefined set of SecurityPermission flags.
  773. LogLog.Debug(declaringType, "Security exception while trying to get current thread ID. Error Ignored. Empty thread name.");
  774. // As a last resort use the hash code of the Thread object
  775. m_data.ThreadName = System.Threading.Thread.CurrentThread.GetHashCode().ToString(System.Globalization.CultureInfo.InvariantCulture);
  776. }
  777. }
  778. #endif
  779. }
  780. return m_data.ThreadName;
  781. }
  782. }
  783. /// <summary>
  784. /// Gets the name of the current user.
  785. /// </summary>
  786. /// <value>
  787. /// The name of the current user, or <c>NOT AVAILABLE</c> when the
  788. /// underlying runtime has no support for retrieving the name of the
  789. /// current user.
  790. /// </value>
  791. /// <remarks>
  792. /// <para>
  793. /// Calls <c>WindowsIdentity.GetCurrent().Name</c> to get the name of
  794. /// the current windows user.
  795. /// </para>
  796. /// <para>
  797. /// To improve performance, we could cache the string representation of
  798. /// the name, and reuse that as long as the identity stayed constant.
  799. /// Once the identity changed, we would need to re-assign and re-render
  800. /// the string.
  801. /// </para>
  802. /// <para>
  803. /// However, the <c>WindowsIdentity.GetCurrent()</c> call seems to
  804. /// return different objects every time, so the current implementation
  805. /// doesn't do this type of caching.
  806. /// </para>
  807. /// <para>
  808. /// Timing for these operations:
  809. /// </para>
  810. /// <list type="table">
  811. /// <listheader>
  812. /// <term>Method</term>
  813. /// <description>Results</description>
  814. /// </listheader>
  815. /// <item>
  816. /// <term><c>WindowsIdentity.GetCurrent()</c></term>
  817. /// <description>10000 loops, 00:00:00.2031250 seconds</description>
  818. /// </item>
  819. /// <item>
  820. /// <term><c>WindowsIdentity.GetCurrent().Name</c></term>
  821. /// <description>10000 loops, 00:00:08.0468750 seconds</description>
  822. /// </item>
  823. /// </list>
  824. /// <para>
  825. /// This means we could speed things up almost 40 times by caching the
  826. /// value of the <c>WindowsIdentity.GetCurrent().Name</c> property, since
  827. /// this takes (8.04-0.20) = 7.84375 seconds.
  828. /// </para>
  829. /// </remarks>
  830. public string UserName
  831. {
  832. get
  833. {
  834. if (m_data.UserName == null && this.m_cacheUpdatable)
  835. {
  836. #if (NETCF || SSCLI || NETSTANDARD1_3) // NETSTANDARD1_3 TODO requires platform-specific code
  837. // On compact framework there's no notion of current Windows user
  838. m_data.UserName = SystemInfo.NotAvailableText;
  839. #else
  840. try
  841. {
  842. WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
  843. if (windowsIdentity != null && windowsIdentity.Name != null)
  844. {
  845. m_data.UserName = windowsIdentity.Name;
  846. }
  847. else
  848. {
  849. m_data.UserName = "";
  850. }
  851. }
  852. catch(System.Security.SecurityException)
  853. {
  854. // This security exception will occur if the caller does not have
  855. // some undefined set of SecurityPermission flags.
  856. LogLog.Debug(declaringType, "Security exception while trying to get current windows identity. Error Ignored. Empty user name.");
  857. m_data.UserName = "";
  858. }
  859. #endif
  860. }
  861. return m_data.UserName;
  862. }
  863. }
  864. /// <summary>
  865. /// Gets the identity of the current thread principal.
  866. /// </summary>
  867. /// <value>
  868. /// The string name of the identity of the current thread principal.
  869. /// </value>
  870. /// <remarks>
  871. /// <para>
  872. /// Calls <c>System.Threading.Thread.CurrentPrincipal.Identity.Name</c> to get
  873. /// the name of the current thread principal.
  874. /// </para>
  875. /// </remarks>
  876. public string Identity
  877. {
  878. get
  879. {
  880. if (m_data.Identity == null && this.m_cacheUpdatable)
  881. {
  882. #if (NETCF || SSCLI || NETSTANDARD1_3)
  883. // On compact framework there's no notion of current thread principals
  884. m_data.Identity = SystemInfo.NotAvailableText;
  885. #else
  886. try
  887. {
  888. if (System.Threading.Thread.CurrentPrincipal != null &&
  889. System.Threading.Thread.CurrentPrincipal.Identity != null &&
  890. System.Threading.Thread.CurrentPrincipal.Identity.Name != null)
  891. {
  892. m_data.Identity = System.Threading.Thread.CurrentPrincipal.Identity.Name;
  893. }
  894. else
  895. {
  896. m_data.Identity = "";
  897. }
  898. }
  899. catch (ObjectDisposedException)
  900. {
  901. // This exception will occur if System.Threading.Thread.CurrentPrincipal.Identity is not null but
  902. // the getter of the property Name tries to access disposed objects.
  903. // Seen to happen on IIS 7 or greater with windows authentication.
  904. LogLog.Debug(declaringType, "Object disposed exception while trying to get current thread principal. Error Ignored. Empty identity name.");
  905. m_data.Identity = "";
  906. }
  907. catch (System.Security.SecurityException)
  908. {
  909. // This security exception will occur if the caller does not have
  910. // some undefined set of SecurityPermission flags.
  911. LogLog.Debug(declaringType, "Security exception while trying to get current thread principal. Error Ignored. Empty identity name.");
  912. m_data.Identity = "";
  913. }
  914. #endif
  915. }
  916. return m_data.Identity;
  917. }
  918. }
  919. /// <summary>
  920. /// Gets the AppDomain friendly name.
  921. /// </summary>
  922. /// <value>
  923. /// The AppDomain friendly name.
  924. /// </value>
  925. /// <remarks>
  926. /// <para>
  927. /// Gets the AppDomain friendly name.
  928. /// </para>
  929. /// </remarks>
  930. public string Domain
  931. {
  932. get
  933. {
  934. if (m_data.Domain == null && this.m_cacheUpdatable)
  935. {
  936. m_data.Domain = SystemInfo.ApplicationFriendlyName;
  937. }
  938. return m_data.Domain;
  939. }
  940. }
  941. /// <summary>
  942. /// Additional event specific properties.
  943. /// </summary>
  944. /// <value>
  945. /// Additional event specific properties.
  946. /// </value>
  947. /// <remarks>
  948. /// <para>
  949. /// A logger or an appender may attach additional
  950. /// properties to specific events. These properties
  951. /// have a string key and an object value.
  952. /// </para>
  953. /// <para>
  954. /// This property is for events that have been added directly to
  955. /// this event. The aggregate properties (which include these
  956. /// event properties) can be retrieved using <see cref="LookupProperty"/>
  957. /// and <see cref="GetProperties"/>.
  958. /// </para>
  959. /// <para>
  960. /// Once the properties have been fixed <see cref="Fix"/> this property
  961. /// returns the combined cached properties. This ensures that updates to
  962. /// this property are always reflected in the underlying storage. When
  963. /// returning the combined properties there may be more keys in the
  964. /// Dictionary than expected.
  965. /// </para>
  966. /// </remarks>
  967. public PropertiesDictionary Properties
  968. {
  969. get
  970. {
  971. // If we have cached properties then return that otherwise changes will be lost
  972. if (m_data.Properties != null)
  973. {
  974. return m_data.Properties;
  975. }
  976. if (m_eventProperties == null)
  977. {
  978. m_eventProperties = new PropertiesDictionary();
  979. }
  980. return m_eventProperties;
  981. }
  982. }
  983. /// <summary>
  984. /// The fixed fields in this event
  985. /// </summary>
  986. /// <value>
  987. /// The set of fields that are fixed in this event
  988. /// </value>
  989. /// <remarks>
  990. /// <para>
  991. /// Fields will not be fixed if they have previously been fixed.
  992. /// It is not possible to 'unfix' a field.
  993. /// </para>
  994. /// </remarks>
  995. public FixFlags Fix
  996. {
  997. get { return m_fixFlags; }
  998. set { this.FixVolatileData(value); }
  999. }
  1000. #endregion Public Instance Properties
  1001. #region Implementation of ISerializable
  1002. #if !NETCF
  1003. /// <summary>
  1004. /// Serializes this object into the <see cref="SerializationInfo" /> provided.
  1005. /// </summary>
  1006. /// <param name="info">The <see cref="SerializationInfo" /> to populate with data.</param>
  1007. /// <param name="context">The destination for this serialization.</param>
  1008. /// <remarks>
  1009. /// <para>
  1010. /// The data in this event must be fixed before it can be serialized.
  1011. /// </para>
  1012. /// <para>
  1013. /// The <see cref="M:FixVolatileData()"/> method must be called during the
  1014. /// <see cref="log4net.Appender.IAppender.DoAppend"/> method call if this event
  1015. /// is to be used outside that method.
  1016. /// </para>
  1017. /// </remarks>
  1018. #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
  1019. [System.Security.SecurityCritical]
  1020. #else
  1021. [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter=true)]
  1022. #endif
  1023. public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  1024. {
  1025. // The caller must call FixVolatileData before this object
  1026. // can be serialized.
  1027. info.AddValue("LoggerName", m_data.LoggerName);
  1028. info.AddValue("Level", m_data.Level);
  1029. info.AddValue("Message", m_data.Message);
  1030. info.AddValue("ThreadName", m_data.ThreadName);
  1031. // TODO: consider serializing UTC rather than local time. Not implemented here because it
  1032. // would give an unexpected result if client and server have different versions of this class.
  1033. // info.AddValue("TimeStamp", m_data.TimeStampUtc);
  1034. #pragma warning disable 618
  1035. info.AddValue("TimeStamp", m_data.TimeStamp);
  1036. #pragma warning restore 618
  1037. info.AddValue("LocationInfo", m_data.LocationInfo);
  1038. info.AddValue("UserName", m_data.UserName);
  1039. info.AddValue("ExceptionString", m_data.ExceptionString);
  1040. info.AddValue("Properties", m_data.Properties);
  1041. info.AddValue("Domain", m_data.Domain);
  1042. info.AddValue("Identity", m_data.Identity);
  1043. }
  1044. #endif
  1045. #endregion Implementation of ISerializable
  1046. #region Public Instance Methods
  1047. /// <summary>
  1048. /// Gets the portable data for this <see cref="LoggingEvent" />.
  1049. /// </summary>
  1050. /// <returns>The <see cref="LoggingEventData"/> for this event.</returns>
  1051. /// <remarks>
  1052. /// <para>
  1053. /// A new <see cref="LoggingEvent"/> can be constructed using a
  1054. /// <see cref="LoggingEventData"/> instance.
  1055. /// </para>
  1056. /// <para>
  1057. /// Does a <see cref="FixFlags.Partial"/> fix of the data
  1058. /// in the logging event before returning the event data.
  1059. /// </para>
  1060. /// </remarks>
  1061. public LoggingEventData GetLoggingEventData()
  1062. {
  1063. return GetLoggingEventData(FixFlags.Partial);
  1064. }
  1065. /// <summary>
  1066. /// Gets the portable data for this <see cref="LoggingEvent" />.
  1067. /// </summary>
  1068. /// <param name="fixFlags">The set of data to ensure is fixed in the LoggingEventData</param>
  1069. /// <returns>The <see cref="LoggingEventData"/> for this event.</returns>
  1070. /// <remarks>
  1071. /// <para>
  1072. /// A new <see cref="LoggingEvent"/> can be constructed using a
  1073. /// <see cref="LoggingEventData"/> instance.
  1074. /// </para>
  1075. /// </remarks>
  1076. public LoggingEventData GetLoggingEventData(FixFlags fixFlags)
  1077. {
  1078. Fix = fixFlags;
  1079. return m_data;
  1080. }
  1081. /// <summary>
  1082. /// Returns this event's exception's rendered using the
  1083. /// <see cref="ILoggerRepository.RendererMap" />.
  1084. /// </summary>
  1085. /// <returns>
  1086. /// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />.
  1087. /// </returns>
  1088. /// <remarks>
  1089. /// <para>
  1090. /// <b>Obsolete. Use <see cref="GetExceptionString"/> instead.</b>
  1091. /// </para>
  1092. /// </remarks>
  1093. [Obsolete("Use GetExceptionString instead")]
  1094. public string GetExceptionStrRep()
  1095. {
  1096. return GetExceptionString();
  1097. }
  1098. /// <summary>
  1099. /// Returns this event's exception's rendered using the
  1100. /// <see cref="ILoggerRepository.RendererMap" />.
  1101. /// </summary>
  1102. /// <returns>
  1103. /// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />.
  1104. /// </returns>
  1105. /// <remarks>
  1106. /// <para>
  1107. /// Returns this event's exception's rendered using the
  1108. /// <see cref="ILoggerRepository.RendererMap" />.
  1109. /// </para>
  1110. /// </remarks>
  1111. public string GetExceptionString()
  1112. {
  1113. if (m_data.ExceptionString == null && this.m_cacheUpdatable)
  1114. {
  1115. if (m_thrownException != null)
  1116. {
  1117. if (m_repository != null)
  1118. {
  1119. // Render exception using the repositories renderer map
  1120. m_data.ExceptionString = m_repository.RendererMap.FindAndRender(m_thrownException);
  1121. }
  1122. else
  1123. {
  1124. // Very last resort
  1125. m_data.ExceptionString = m_thrownException.ToString();
  1126. }
  1127. }
  1128. else
  1129. {
  1130. m_data.ExceptionString = "";
  1131. }
  1132. }
  1133. return m_data.ExceptionString;
  1134. }
  1135. /// <summary>
  1136. /// Fix instance fields that hold volatile data.
  1137. /// </summary>
  1138. /// <remarks>
  1139. /// <para>
  1140. /// Some of the values in instances of <see cref="LoggingEvent"/>
  1141. /// are considered volatile, that is the values are correct at the
  1142. /// time the event is delivered to appenders, but will not be consistent
  1143. /// at any time afterwards. If an event is to be stored and then processed
  1144. /// at a later time these volatile values must be fixed by calling
  1145. /// <see cref="M:FixVolatileData()"/>. There is a performance penalty
  1146. /// incurred by calling <see cref="M:FixVolatileData()"/> but it
  1147. /// is essential to maintaining data consistency.
  1148. /// </para>
  1149. /// <para>
  1150. /// Calling <see cref="M:FixVolatileData()"/> is equivalent to
  1151. /// calling <see cref="M:FixVolatileData(bool)"/> passing the parameter
  1152. /// <c>false</c>.
  1153. /// </para>
  1154. /// <para>
  1155. /// See <see cref="M:FixVolatileData(bool)"/> for more
  1156. /// information.
  1157. /// </para>
  1158. /// </remarks>
  1159. [Obsolete("Use Fix property")]
  1160. public void FixVolatileData()
  1161. {
  1162. Fix = FixFlags.All;
  1163. }
  1164. /// <summary>
  1165. /// Fixes instance fields that hold volatile data.
  1166. /// </summary>
  1167. /// <param name="fastButLoose">Set to <c>true</c> to not fix data that takes a long time to fix.</param>
  1168. /// <remarks>
  1169. /// <para>
  1170. /// Some of the values in instances of <see cref="LoggingEvent"/>
  1171. /// are considered volatile, that is the values are correct at the
  1172. /// time the event is delivered to appenders, but will not be consistent
  1173. /// at any time afterwards. If an event is to be stored and then processed
  1174. /// at a later time these volatile values must be fixed by calling
  1175. /// <see cref="M:FixVolatileData()"/>. There is a performance penalty
  1176. /// for incurred by calling <see cref="M:FixVolatileData()"/> but it
  1177. /// is essential to maintaining data consistency.
  1178. /// </para>
  1179. /// <para>
  1180. /// The <paramref name="fastButLoose"/> param controls the data that
  1181. /// is fixed. Some of the data that can be fixed takes a long time to
  1182. /// generate, therefore if you do not require those settings to be fixed
  1183. /// they can be ignored by setting the <paramref name="fastButLoose"/> param
  1184. /// to <c>true</c>. This setting will ignore the <see cref="LocationInformation"/>
  1185. /// and <see cref="UserName"/> settings.
  1186. /// </para>
  1187. /// <para>
  1188. /// Set <paramref name="fastButLoose"/> to <c>false</c> to ensure that all
  1189. /// settings are fixed.
  1190. /// </para>
  1191. /// </remarks>
  1192. [Obsolete("Use Fix property")]
  1193. public void FixVolatileData(bool fastButLoose)
  1194. {
  1195. if (fastButLoose)
  1196. {
  1197. Fix = FixFlags.Partial;
  1198. }
  1199. else
  1200. {
  1201. Fix = FixFlags.All;
  1202. }
  1203. }
  1204. /// <summary>
  1205. /// Fix the fields specified by the <see cref="FixFlags"/> parameter
  1206. /// </summary>
  1207. /// <param name="flags">the fields to fix</param>
  1208. /// <remarks>
  1209. /// <para>
  1210. /// Only fields specified in the <paramref name="flags"/> will be fixed.
  1211. /// Fields will not be fixed if they have previously been fixed.
  1212. /// It is not possible to 'unfix' a field.
  1213. /// </para>
  1214. /// </remarks>
  1215. protected void FixVolatileData(FixFlags flags)
  1216. {
  1217. object forceCreation = null;
  1218. //Unlock the cache so that new values can be stored
  1219. //This may not be ideal if we are no longer in the correct context
  1220. //and someone calls fix.
  1221. m_cacheUpdatable=true;
  1222. // determine the flags that we are actually fixing
  1223. FixFlags updateFlags = (FixFlags)((flags ^ m_fixFlags) & flags);
  1224. if (updateFlags > 0)
  1225. {
  1226. if ((updateFlags & FixFlags.Message) != 0)
  1227. {
  1228. // Force the message to be rendered
  1229. forceCreation = this.RenderedMessage;
  1230. m_fixFlags |= FixFlags.Message;
  1231. }
  1232. if ((updateFlags & FixFlags.ThreadName) != 0)
  1233. {
  1234. // Grab the thread name
  1235. forceCreation = this.ThreadName;
  1236. m_fixFlags |= FixFlags.ThreadName;
  1237. }
  1238. if ((updateFlags & FixFlags.LocationInfo) != 0)
  1239. {
  1240. // Force the location information to be loaded
  1241. forceCreation = this.LocationInformation;
  1242. m_fixFlags |= FixFlags.LocationInfo;
  1243. }
  1244. if ((updateFlags & FixFlags.UserName) != 0)
  1245. {
  1246. // Grab the user name
  1247. forceCreation = this.UserName;
  1248. m_fixFlags |= FixFlags.UserName;
  1249. }
  1250. if ((updateFlags & FixFlags.Domain) != 0)
  1251. {
  1252. // Grab the domain name
  1253. forceCreation = this.Domain;
  1254. m_fixFlags |= FixFlags.Domain;
  1255. }
  1256. if ((updateFlags & FixFlags.Identity) != 0)
  1257. {
  1258. // Grab the identity
  1259. forceCreation = this.Identity;
  1260. m_fixFlags |= FixFlags.Identity;
  1261. }
  1262. if ((updateFlags & FixFlags.Exception) != 0)
  1263. {
  1264. // Force the exception text to be loaded
  1265. forceCreation = GetExceptionString();
  1266. m_fixFlags |= FixFlags.Exception;
  1267. }
  1268. if ((updateFlags & FixFlags.Properties) != 0)
  1269. {
  1270. CacheProperties();
  1271. m_fixFlags |= FixFlags.Properties;
  1272. }
  1273. }
  1274. // avoid warning CS0219
  1275. if (forceCreation != null)
  1276. {
  1277. }
  1278. //Finaly lock everything we've cached.
  1279. m_cacheUpdatable=false;
  1280. }
  1281. #endregion Public Instance Methods
  1282. #region Protected Instance Methods
  1283. private void CreateCompositeProperties()
  1284. {
  1285. CompositeProperties compositeProperties = new CompositeProperties();
  1286. if (m_eventProperties != null)
  1287. {
  1288. compositeProperties.Add(m_eventProperties);
  1289. }
  1290. #if !NETCF
  1291. PropertiesDictionary logicalThreadProperties = LogicalThreadContext.Properties.GetProperties(false);
  1292. if (logicalThreadProperties != null)
  1293. {
  1294. compositeProperties.Add(logicalThreadProperties);
  1295. }
  1296. #endif
  1297. PropertiesDictionary threadProperties = ThreadContext.Properties.GetProperties(false);
  1298. if (threadProperties != null)
  1299. {
  1300. compositeProperties.Add(threadProperties);
  1301. }
  1302. // TODO: Add Repository Properties
  1303. // event properties
  1304. PropertiesDictionary eventProperties = new PropertiesDictionary();
  1305. eventProperties[UserNameProperty] = UserName;
  1306. eventProperties[IdentityProperty] = Identity;
  1307. compositeProperties.Add(eventProperties);
  1308. compositeProperties.Add(GlobalContext.Properties.GetReadOnlyProperties());
  1309. m_compositeProperties = compositeProperties;
  1310. }
  1311. private void CacheProperties()
  1312. {
  1313. if (m_data.Properties == null && this.m_cacheUpdatable)
  1314. {
  1315. if (m_compositeProperties == null)
  1316. {
  1317. CreateCompositeProperties();
  1318. }
  1319. PropertiesDictionary flattenedProperties = m_compositeProperties.Flatten();
  1320. PropertiesDictionary fixedProperties = new PropertiesDictionary();
  1321. // Validate properties
  1322. foreach(DictionaryEntry entry in flattenedProperties)
  1323. {
  1324. string key = entry.Key as string;
  1325. if (key != null)
  1326. {
  1327. object val = entry.Value;
  1328. // Fix any IFixingRequired objects
  1329. IFixingRequired fixingRequired = val as IFixingRequired;
  1330. if (fixingRequired != null)
  1331. {
  1332. val = fixingRequired.GetFixedObject();
  1333. }
  1334. // Strip keys with null values
  1335. if (val != null)
  1336. {
  1337. fixedProperties[key] = val;
  1338. }
  1339. }
  1340. }
  1341. m_data.Properties = fixedProperties;
  1342. }
  1343. }
  1344. /// <summary>
  1345. /// Lookup a composite property in this event
  1346. /// </summary>
  1347. /// <param name="key">the key for the property to lookup</param>
  1348. /// <returns>the value for the property</returns>
  1349. /// <remarks>
  1350. /// <para>
  1351. /// This event has composite properties that combine together properties from
  1352. /// several different contexts in the following order:
  1353. /// <list type="definition">
  1354. /// <item>
  1355. /// <term>this events properties</term>
  1356. /// <description>
  1357. /// This event has <see cref="Properties"/> that can be set. These
  1358. /// properties are specific to this event only.
  1359. /// </description>
  1360. /// </item>
  1361. /// <item>
  1362. /// <term>the thread properties</term>
  1363. /// <description>
  1364. /// The <see cref="ThreadContext.Properties"/> that are set on the current
  1365. /// thread. These properties are shared by all events logged on this thread.
  1366. /// </description>
  1367. /// </item>
  1368. /// <item>
  1369. /// <term>the global properties</term>
  1370. /// <description>
  1371. /// The <see cref="GlobalContext.Properties"/> that are set globally. These
  1372. /// properties are shared by all the threads in the AppDomain.
  1373. /// </description>
  1374. /// </item>
  1375. /// </list>
  1376. /// </para>
  1377. /// </remarks>
  1378. public object LookupProperty(string key)
  1379. {
  1380. if (m_data.Properties != null)
  1381. {
  1382. return m_data.Properties[key];
  1383. }
  1384. if (m_compositeProperties == null)
  1385. {
  1386. CreateCompositeProperties();
  1387. }
  1388. return m_compositeProperties[key];
  1389. }
  1390. /// <summary>
  1391. /// Get all the composite properties in this event
  1392. /// </summary>
  1393. /// <returns>the <see cref="PropertiesDictionary"/> containing all the properties</returns>
  1394. /// <remarks>
  1395. /// <para>
  1396. /// See <see cref="LookupProperty"/> for details of the composite properties
  1397. /// stored by the event.
  1398. /// </para>
  1399. /// <para>
  1400. /// This method returns a single <see cref="PropertiesDictionary"/> containing all the
  1401. /// properties defined for this event.
  1402. /// </para>
  1403. /// </remarks>
  1404. public PropertiesDictionary GetProperties()
  1405. {
  1406. if (m_data.Properties != null)
  1407. {
  1408. return m_data.Properties;
  1409. }
  1410. if (m_compositeProperties == null)
  1411. {
  1412. CreateCompositeProperties();
  1413. }
  1414. return m_compositeProperties.Flatten();
  1415. }
  1416. #endregion Public Instance Methods
  1417. #region Private Instance Fields
  1418. /// <summary>
  1419. /// The internal logging event data.
  1420. /// </summary>
  1421. private LoggingEventData m_data;
  1422. /// <summary>
  1423. /// The internal logging event data.
  1424. /// </summary>
  1425. private CompositeProperties m_compositeProperties;
  1426. /// <summary>
  1427. /// The internal logging event data.
  1428. /// </summary>
  1429. private PropertiesDictionary m_eventProperties;
  1430. /// <summary>
  1431. /// The fully qualified Type of the calling
  1432. /// logger class in the stack frame (i.e. the declaring type of the method).
  1433. /// </summary>
  1434. private readonly Type m_callerStackBoundaryDeclaringType;
  1435. /// <summary>
  1436. /// The application supplied message of logging event.
  1437. /// </summary>
  1438. private readonly object m_message;
  1439. /// <summary>
  1440. /// The exception that was thrown.
  1441. /// </summary>
  1442. /// <remarks>
  1443. /// This is not serialized. The string representation
  1444. /// is serialized instead.
  1445. /// </remarks>
  1446. private readonly Exception m_thrownException;
  1447. /// <summary>
  1448. /// The repository that generated the logging event
  1449. /// </summary>
  1450. /// <remarks>
  1451. /// This is not serialized.
  1452. /// </remarks>
  1453. private ILoggerRepository m_repository = null;
  1454. /// <summary>
  1455. /// The fix state for this event
  1456. /// </summary>
  1457. /// <remarks>
  1458. /// These flags indicate which fields have been fixed.
  1459. /// Not serialized.
  1460. /// </remarks>
  1461. private FixFlags m_fixFlags = FixFlags.None;
  1462. /// <summary>
  1463. /// Indicated that the internal cache is updateable (ie not fixed)
  1464. /// </summary>
  1465. /// <remarks>
  1466. /// This is a seperate flag to m_fixFlags as it allows incrementel fixing and simpler
  1467. /// changes in the caching strategy.
  1468. /// </remarks>
  1469. private bool m_cacheUpdatable = true;
  1470. #endregion Private Instance Fields
  1471. #region Constants
  1472. /// <summary>
  1473. /// The key into the Properties map for the host name value.
  1474. /// </summary>
  1475. public const string HostNameProperty = "log4net:HostName";
  1476. /// <summary>
  1477. /// The key into the Properties map for the thread identity value.
  1478. /// </summary>
  1479. public const string IdentityProperty = "log4net:Identity";
  1480. /// <summary>
  1481. /// The key into the Properties map for the user name value.
  1482. /// </summary>
  1483. public const string UserNameProperty = "log4net:UserName";
  1484. #endregion
  1485. }
  1486. }