FileAppender.cs 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  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.IO;
  21. using System.Text;
  22. using System.Threading;
  23. using log4net.Util;
  24. using log4net.Layout;
  25. using log4net.Core;
  26. #if NET_4_5 || NETSTANDARD1_3
  27. using System.Threading.Tasks;
  28. #endif
  29. namespace log4net.Appender
  30. {
  31. #if !NETCF
  32. /// <summary>
  33. /// Appends logging events to a file.
  34. /// </summary>
  35. /// <remarks>
  36. /// <para>
  37. /// Logging events are sent to the file specified by
  38. /// the <see cref="File"/> property.
  39. /// </para>
  40. /// <para>
  41. /// The file can be opened in either append or overwrite mode
  42. /// by specifying the <see cref="AppendToFile"/> property.
  43. /// If the file path is relative it is taken as relative from
  44. /// the application base directory. The file encoding can be
  45. /// specified by setting the <see cref="Encoding"/> property.
  46. /// </para>
  47. /// <para>
  48. /// The layout's <see cref="ILayout.Header"/> and <see cref="ILayout.Footer"/>
  49. /// values will be written each time the file is opened and closed
  50. /// respectively. If the <see cref="AppendToFile"/> property is <see langword="true"/>
  51. /// then the file may contain multiple copies of the header and footer.
  52. /// </para>
  53. /// <para>
  54. /// This appender will first try to open the file for writing when <see cref="ActivateOptions"/>
  55. /// is called. This will typically be during configuration.
  56. /// If the file cannot be opened for writing the appender will attempt
  57. /// to open the file again each time a message is logged to the appender.
  58. /// If the file cannot be opened for writing when a message is logged then
  59. /// the message will be discarded by this appender.
  60. /// </para>
  61. /// <para>
  62. /// The <see cref="FileAppender"/> supports pluggable file locking models via
  63. /// the <see cref="LockingModel"/> property.
  64. /// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/>
  65. /// is to obtain an exclusive write lock on the file until this appender is closed.
  66. /// The alternative models only hold a
  67. /// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>)
  68. /// or synchronize by using a named system wide Mutex (<see cref="FileAppender.InterProcessLock"/>).
  69. /// </para>
  70. /// <para>
  71. /// All locking strategies have issues and you should seriously consider using a different strategy that
  72. /// avoids having multiple processes logging to the same file.
  73. /// </para>
  74. /// </remarks>
  75. /// <author>Nicko Cadell</author>
  76. /// <author>Gert Driesen</author>
  77. /// <author>Rodrigo B. de Oliveira</author>
  78. /// <author>Douglas de la Torre</author>
  79. /// <author>Niall Daley</author>
  80. #else
  81. /// <summary>
  82. /// Appends logging events to a file.
  83. /// </summary>
  84. /// <remarks>
  85. /// <para>
  86. /// Logging events are sent to the file specified by
  87. /// the <see cref="File"/> property.
  88. /// </para>
  89. /// <para>
  90. /// The file can be opened in either append or overwrite mode
  91. /// by specifying the <see cref="AppendToFile"/> property.
  92. /// If the file path is relative it is taken as relative from
  93. /// the application base directory. The file encoding can be
  94. /// specified by setting the <see cref="Encoding"/> property.
  95. /// </para>
  96. /// <para>
  97. /// The layout's <see cref="ILayout.Header"/> and <see cref="ILayout.Footer"/>
  98. /// values will be written each time the file is opened and closed
  99. /// respectively. If the <see cref="AppendToFile"/> property is <see langword="true"/>
  100. /// then the file may contain multiple copies of the header and footer.
  101. /// </para>
  102. /// <para>
  103. /// This appender will first try to open the file for writing when <see cref="ActivateOptions"/>
  104. /// is called. This will typically be during configuration.
  105. /// If the file cannot be opened for writing the appender will attempt
  106. /// to open the file again each time a message is logged to the appender.
  107. /// If the file cannot be opened for writing when a message is logged then
  108. /// the message will be discarded by this appender.
  109. /// </para>
  110. /// <para>
  111. /// The <see cref="FileAppender"/> supports pluggable file locking models via
  112. /// the <see cref="LockingModel"/> property.
  113. /// The default behavior, implemented by <see cref="FileAppender.ExclusiveLock"/>
  114. /// is to obtain an exclusive write lock on the file until this appender is closed.
  115. /// The alternative model only holds a
  116. /// write lock while the appender is writing a logging event (<see cref="FileAppender.MinimalLock"/>).
  117. /// </para>
  118. /// <para>
  119. /// All locking strategies have issues and you should seriously consider using a different strategy that
  120. /// avoids having multiple processes logging to the same file.
  121. /// </para>
  122. /// </remarks>
  123. /// <author>Nicko Cadell</author>
  124. /// <author>Gert Driesen</author>
  125. /// <author>Rodrigo B. de Oliveira</author>
  126. /// <author>Douglas de la Torre</author>
  127. /// <author>Niall Daley</author>
  128. #endif
  129. public class FileAppender : TextWriterAppender
  130. {
  131. #region LockingStream Inner Class
  132. /// <summary>
  133. /// Write only <see cref="Stream"/> that uses the <see cref="LockingModelBase"/>
  134. /// to manage access to an underlying resource.
  135. /// </summary>
  136. private sealed class LockingStream : Stream, IDisposable
  137. {
  138. public sealed class LockStateException : LogException
  139. {
  140. public LockStateException(string message)
  141. : base(message)
  142. {
  143. }
  144. }
  145. private Stream m_realStream = null;
  146. private LockingModelBase m_lockingModel = null;
  147. private int m_lockLevel = 0;
  148. public LockingStream(LockingModelBase locking)
  149. : base()
  150. {
  151. if (locking == null)
  152. {
  153. throw new ArgumentException("Locking model may not be null", "locking");
  154. }
  155. m_lockingModel = locking;
  156. }
  157. #region Override Implementation of Stream
  158. #if NETSTANDARD1_3
  159. protected override void Dispose(bool disposing)
  160. {
  161. m_lockingModel.CloseFile();
  162. base.Dispose(disposing);
  163. }
  164. #else
  165. private int m_readTotal = -1;
  166. // Methods
  167. public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  168. {
  169. AssertLocked();
  170. IAsyncResult ret = m_realStream.BeginRead(buffer, offset, count, callback, state);
  171. m_readTotal = EndRead(ret);
  172. return ret;
  173. }
  174. /// <summary>
  175. /// True asynchronous writes are not supported, the implementation forces a synchronous write.
  176. /// </summary>
  177. public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  178. {
  179. AssertLocked();
  180. IAsyncResult ret = m_realStream.BeginWrite(buffer, offset, count, callback, state);
  181. EndWrite(ret);
  182. return ret;
  183. }
  184. public override void Close()
  185. {
  186. m_lockingModel.CloseFile();
  187. }
  188. public override int EndRead(IAsyncResult asyncResult)
  189. {
  190. AssertLocked();
  191. return m_readTotal;
  192. }
  193. public override void EndWrite(IAsyncResult asyncResult)
  194. {
  195. //No-op, it has already been handled
  196. }
  197. #endif
  198. #if NET_4_5 || NETSTANDARD1_3
  199. public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  200. {
  201. AssertLocked();
  202. return m_realStream.ReadAsync(buffer, offset, count, cancellationToken);
  203. }
  204. public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  205. {
  206. AssertLocked();
  207. return base.WriteAsync(buffer, offset, count, cancellationToken);
  208. }
  209. #endif
  210. public override void Flush()
  211. {
  212. AssertLocked();
  213. m_realStream.Flush();
  214. }
  215. public override int Read(byte[] buffer, int offset, int count)
  216. {
  217. return m_realStream.Read(buffer, offset, count);
  218. }
  219. public override int ReadByte()
  220. {
  221. return m_realStream.ReadByte();
  222. }
  223. public override long Seek(long offset, SeekOrigin origin)
  224. {
  225. AssertLocked();
  226. return m_realStream.Seek(offset, origin);
  227. }
  228. public override void SetLength(long value)
  229. {
  230. AssertLocked();
  231. m_realStream.SetLength(value);
  232. }
  233. void IDisposable.Dispose()
  234. {
  235. #if NETSTANDARD1_3
  236. Dispose(true);
  237. #else
  238. Close();
  239. #endif
  240. }
  241. public override void Write(byte[] buffer, int offset, int count)
  242. {
  243. AssertLocked();
  244. m_realStream.Write(buffer, offset, count);
  245. }
  246. public override void WriteByte(byte value)
  247. {
  248. AssertLocked();
  249. m_realStream.WriteByte(value);
  250. }
  251. // Properties
  252. public override bool CanRead
  253. {
  254. get { return false; }
  255. }
  256. public override bool CanSeek
  257. {
  258. get
  259. {
  260. AssertLocked();
  261. return m_realStream.CanSeek;
  262. }
  263. }
  264. public override bool CanWrite
  265. {
  266. get
  267. {
  268. AssertLocked();
  269. return m_realStream.CanWrite;
  270. }
  271. }
  272. public override long Length
  273. {
  274. get
  275. {
  276. AssertLocked();
  277. return m_realStream.Length;
  278. }
  279. }
  280. public override long Position
  281. {
  282. get
  283. {
  284. AssertLocked();
  285. return m_realStream.Position;
  286. }
  287. set
  288. {
  289. AssertLocked();
  290. m_realStream.Position = value;
  291. }
  292. }
  293. #endregion Override Implementation of Stream
  294. #region Locking Methods
  295. private void AssertLocked()
  296. {
  297. if (m_realStream == null)
  298. {
  299. throw new LockStateException("The file is not currently locked");
  300. }
  301. }
  302. public bool AcquireLock()
  303. {
  304. bool ret = false;
  305. lock (this)
  306. {
  307. if (m_lockLevel == 0)
  308. {
  309. // If lock is already acquired, nop
  310. m_realStream = m_lockingModel.AcquireLock();
  311. }
  312. if (m_realStream != null)
  313. {
  314. m_lockLevel++;
  315. ret = true;
  316. }
  317. }
  318. return ret;
  319. }
  320. public void ReleaseLock()
  321. {
  322. lock (this)
  323. {
  324. m_lockLevel--;
  325. if (m_lockLevel == 0)
  326. {
  327. // If already unlocked, nop
  328. m_lockingModel.ReleaseLock();
  329. m_realStream = null;
  330. }
  331. }
  332. }
  333. #endregion Locking Methods
  334. }
  335. #endregion LockingStream Inner Class
  336. #region Locking Models
  337. /// <summary>
  338. /// Locking model base class
  339. /// </summary>
  340. /// <remarks>
  341. /// <para>
  342. /// Base class for the locking models available to the <see cref="FileAppender"/> derived loggers.
  343. /// </para>
  344. /// </remarks>
  345. public abstract class LockingModelBase
  346. {
  347. private FileAppender m_appender = null;
  348. /// <summary>
  349. /// Open the output file
  350. /// </summary>
  351. /// <param name="filename">The filename to use</param>
  352. /// <param name="append">Whether to append to the file, or overwrite</param>
  353. /// <param name="encoding">The encoding to use</param>
  354. /// <remarks>
  355. /// <para>
  356. /// Open the file specified and prepare for logging.
  357. /// No writes will be made until <see cref="AcquireLock"/> is called.
  358. /// Must be called before any calls to <see cref="AcquireLock"/>,
  359. /// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
  360. /// </para>
  361. /// </remarks>
  362. public abstract void OpenFile(string filename, bool append, Encoding encoding);
  363. /// <summary>
  364. /// Close the file
  365. /// </summary>
  366. /// <remarks>
  367. /// <para>
  368. /// Close the file. No further writes will be made.
  369. /// </para>
  370. /// </remarks>
  371. public abstract void CloseFile();
  372. /// <summary>
  373. /// Initializes all resources used by this locking model.
  374. /// </summary>
  375. public abstract void ActivateOptions();
  376. /// <summary>
  377. /// Disposes all resources that were initialized by this locking model.
  378. /// </summary>
  379. public abstract void OnClose();
  380. /// <summary>
  381. /// Acquire the lock on the file
  382. /// </summary>
  383. /// <returns>A stream that is ready to be written to.</returns>
  384. /// <remarks>
  385. /// <para>
  386. /// Acquire the lock on the file in preparation for writing to it.
  387. /// Return a stream pointing to the file. <see cref="ReleaseLock"/>
  388. /// must be called to release the lock on the output file.
  389. /// </para>
  390. /// </remarks>
  391. public abstract Stream AcquireLock();
  392. /// <summary>
  393. /// Release the lock on the file
  394. /// </summary>
  395. /// <remarks>
  396. /// <para>
  397. /// Release the lock on the file. No further writes will be made to the
  398. /// stream until <see cref="AcquireLock"/> is called again.
  399. /// </para>
  400. /// </remarks>
  401. public abstract void ReleaseLock();
  402. /// <summary>
  403. /// Gets or sets the <see cref="FileAppender"/> for this LockingModel
  404. /// </summary>
  405. /// <value>
  406. /// The <see cref="FileAppender"/> for this LockingModel
  407. /// </value>
  408. /// <remarks>
  409. /// <para>
  410. /// The file appender this locking model is attached to and working on
  411. /// behalf of.
  412. /// </para>
  413. /// <para>
  414. /// The file appender is used to locate the security context and the error handler to use.
  415. /// </para>
  416. /// <para>
  417. /// The value of this property will be set before <see cref="OpenFile"/> is
  418. /// called.
  419. /// </para>
  420. /// </remarks>
  421. public FileAppender CurrentAppender
  422. {
  423. get { return m_appender; }
  424. set { m_appender = value; }
  425. }
  426. /// <summary>
  427. /// Helper method that creates a FileStream under CurrentAppender's SecurityContext.
  428. /// </summary>
  429. /// <remarks>
  430. /// <para>
  431. /// Typically called during OpenFile or AcquireLock.
  432. /// </para>
  433. /// <para>
  434. /// If the directory portion of the <paramref name="filename"/> does not exist, it is created
  435. /// via Directory.CreateDirecctory.
  436. /// </para>
  437. /// </remarks>
  438. /// <param name="filename"></param>
  439. /// <param name="append"></param>
  440. /// <param name="fileShare"></param>
  441. /// <returns></returns>
  442. protected Stream CreateStream(string filename, bool append, FileShare fileShare)
  443. {
  444. using (CurrentAppender.SecurityContext.Impersonate(this))
  445. {
  446. // Ensure that the directory structure exists
  447. string directoryFullName = Path.GetDirectoryName(filename);
  448. // Only create the directory if it does not exist
  449. // doing this check here resolves some permissions failures
  450. if (!Directory.Exists(directoryFullName))
  451. {
  452. Directory.CreateDirectory(directoryFullName);
  453. }
  454. FileMode fileOpenMode = append ? FileMode.Append : FileMode.Create;
  455. return new FileStream(filename, fileOpenMode, FileAccess.Write, fileShare);
  456. }
  457. }
  458. /// <summary>
  459. /// Helper method to close <paramref name="stream"/> under CurrentAppender's SecurityContext.
  460. /// </summary>
  461. /// <remarks>
  462. /// Does not set <paramref name="stream"/> to null.
  463. /// </remarks>
  464. /// <param name="stream"></param>
  465. protected void CloseStream(Stream stream)
  466. {
  467. using (CurrentAppender.SecurityContext.Impersonate(this))
  468. {
  469. stream.Close();
  470. }
  471. }
  472. }
  473. /// <summary>
  474. /// Hold an exclusive lock on the output file
  475. /// </summary>
  476. /// <remarks>
  477. /// <para>
  478. /// Open the file once for writing and hold it open until <see cref="CloseFile"/> is called.
  479. /// Maintains an exclusive lock on the file during this time.
  480. /// </para>
  481. /// </remarks>
  482. public class ExclusiveLock : LockingModelBase
  483. {
  484. private Stream m_stream = null;
  485. /// <summary>
  486. /// Open the file specified and prepare for logging.
  487. /// </summary>
  488. /// <param name="filename">The filename to use</param>
  489. /// <param name="append">Whether to append to the file, or overwrite</param>
  490. /// <param name="encoding">The encoding to use</param>
  491. /// <remarks>
  492. /// <para>
  493. /// Open the file specified and prepare for logging.
  494. /// No writes will be made until <see cref="AcquireLock"/> is called.
  495. /// Must be called before any calls to <see cref="AcquireLock"/>,
  496. /// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
  497. /// </para>
  498. /// </remarks>
  499. public override void OpenFile(string filename, bool append, Encoding encoding)
  500. {
  501. try
  502. {
  503. m_stream = CreateStream(filename, append, FileShare.Read);
  504. }
  505. catch (Exception e1)
  506. {
  507. CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
  508. }
  509. }
  510. /// <summary>
  511. /// Close the file
  512. /// </summary>
  513. /// <remarks>
  514. /// <para>
  515. /// Close the file. No further writes will be made.
  516. /// </para>
  517. /// </remarks>
  518. public override void CloseFile()
  519. {
  520. CloseStream(m_stream);
  521. m_stream = null;
  522. }
  523. /// <summary>
  524. /// Acquire the lock on the file
  525. /// </summary>
  526. /// <returns>A stream that is ready to be written to.</returns>
  527. /// <remarks>
  528. /// <para>
  529. /// Does nothing. The lock is already taken
  530. /// </para>
  531. /// </remarks>
  532. public override Stream AcquireLock()
  533. {
  534. return m_stream;
  535. }
  536. /// <summary>
  537. /// Release the lock on the file
  538. /// </summary>
  539. /// <remarks>
  540. /// <para>
  541. /// Does nothing. The lock will be released when the file is closed.
  542. /// </para>
  543. /// </remarks>
  544. public override void ReleaseLock()
  545. {
  546. //NOP
  547. }
  548. /// <summary>
  549. /// Initializes all resources used by this locking model.
  550. /// </summary>
  551. public override void ActivateOptions()
  552. {
  553. //NOP
  554. }
  555. /// <summary>
  556. /// Disposes all resources that were initialized by this locking model.
  557. /// </summary>
  558. public override void OnClose()
  559. {
  560. //NOP
  561. }
  562. }
  563. /// <summary>
  564. /// Acquires the file lock for each write
  565. /// </summary>
  566. /// <remarks>
  567. /// <para>
  568. /// Opens the file once for each <see cref="AcquireLock"/>/<see cref="ReleaseLock"/> cycle,
  569. /// thus holding the lock for the minimal amount of time. This method of locking
  570. /// is considerably slower than <see cref="FileAppender.ExclusiveLock"/> but allows
  571. /// other processes to move/delete the log file whilst logging continues.
  572. /// </para>
  573. /// </remarks>
  574. public class MinimalLock : LockingModelBase
  575. {
  576. private string m_filename;
  577. private bool m_append;
  578. private Stream m_stream = null;
  579. /// <summary>
  580. /// Prepares to open the file when the first message is logged.
  581. /// </summary>
  582. /// <param name="filename">The filename to use</param>
  583. /// <param name="append">Whether to append to the file, or overwrite</param>
  584. /// <param name="encoding">The encoding to use</param>
  585. /// <remarks>
  586. /// <para>
  587. /// Open the file specified and prepare for logging.
  588. /// No writes will be made until <see cref="AcquireLock"/> is called.
  589. /// Must be called before any calls to <see cref="AcquireLock"/>,
  590. /// <see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
  591. /// </para>
  592. /// </remarks>
  593. public override void OpenFile(string filename, bool append, Encoding encoding)
  594. {
  595. m_filename = filename;
  596. m_append = append;
  597. }
  598. /// <summary>
  599. /// Close the file
  600. /// </summary>
  601. /// <remarks>
  602. /// <para>
  603. /// Close the file. No further writes will be made.
  604. /// </para>
  605. /// </remarks>
  606. public override void CloseFile()
  607. {
  608. // NOP
  609. }
  610. /// <summary>
  611. /// Acquire the lock on the file
  612. /// </summary>
  613. /// <returns>A stream that is ready to be written to.</returns>
  614. /// <remarks>
  615. /// <para>
  616. /// Acquire the lock on the file in preparation for writing to it.
  617. /// Return a stream pointing to the file. <see cref="ReleaseLock"/>
  618. /// must be called to release the lock on the output file.
  619. /// </para>
  620. /// </remarks>
  621. public override Stream AcquireLock()
  622. {
  623. if (m_stream == null)
  624. {
  625. try
  626. {
  627. m_stream = CreateStream(m_filename, m_append, FileShare.Read);
  628. m_append = true;
  629. }
  630. catch (Exception e1)
  631. {
  632. CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + m_filename + ". " + e1.Message);
  633. }
  634. }
  635. return m_stream;
  636. }
  637. /// <summary>
  638. /// Release the lock on the file
  639. /// </summary>
  640. /// <remarks>
  641. /// <para>
  642. /// Release the lock on the file. No further writes will be made to the
  643. /// stream until <see cref="AcquireLock"/> is called again.
  644. /// </para>
  645. /// </remarks>
  646. public override void ReleaseLock()
  647. {
  648. CloseStream(m_stream);
  649. m_stream = null;
  650. }
  651. /// <summary>
  652. /// Initializes all resources used by this locking model.
  653. /// </summary>
  654. public override void ActivateOptions()
  655. {
  656. //NOP
  657. }
  658. /// <summary>
  659. /// Disposes all resources that were initialized by this locking model.
  660. /// </summary>
  661. public override void OnClose()
  662. {
  663. //NOP
  664. }
  665. }
  666. #if !NETCF
  667. /// <summary>
  668. /// Provides cross-process file locking.
  669. /// </summary>
  670. /// <author>Ron Grabowski</author>
  671. /// <author>Steve Wranovsky</author>
  672. public class InterProcessLock : LockingModelBase
  673. {
  674. private Mutex m_mutex = null;
  675. private Stream m_stream = null;
  676. private int m_recursiveWatch = 0;
  677. /// <summary>
  678. /// Open the file specified and prepare for logging.
  679. /// </summary>
  680. /// <param name="filename">The filename to use</param>
  681. /// <param name="append">Whether to append to the file, or overwrite</param>
  682. /// <param name="encoding">The encoding to use</param>
  683. /// <remarks>
  684. /// <para>
  685. /// Open the file specified and prepare for logging.
  686. /// No writes will be made until <see cref="AcquireLock"/> is called.
  687. /// Must be called before any calls to <see cref="AcquireLock"/>,
  688. /// -<see cref="ReleaseLock"/> and <see cref="CloseFile"/>.
  689. /// </para>
  690. /// </remarks>
  691. #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
  692. [System.Security.SecuritySafeCritical]
  693. #endif
  694. public override void OpenFile(string filename, bool append, Encoding encoding)
  695. {
  696. try
  697. {
  698. m_stream = CreateStream(filename, append, FileShare.ReadWrite);
  699. }
  700. catch (Exception e1)
  701. {
  702. CurrentAppender.ErrorHandler.Error("Unable to acquire lock on file " + filename + ". " + e1.Message);
  703. }
  704. }
  705. /// <summary>
  706. /// Close the file
  707. /// </summary>
  708. /// <remarks>
  709. /// <para>
  710. /// Close the file. No further writes will be made.
  711. /// </para>
  712. /// </remarks>
  713. public override void CloseFile()
  714. {
  715. try
  716. {
  717. CloseStream(m_stream);
  718. m_stream = null;
  719. }
  720. finally
  721. {
  722. ReleaseLock();
  723. }
  724. }
  725. /// <summary>
  726. /// Acquire the lock on the file
  727. /// </summary>
  728. /// <returns>A stream that is ready to be written to.</returns>
  729. /// <remarks>
  730. /// <para>
  731. /// Does nothing. The lock is already taken
  732. /// </para>
  733. /// </remarks>
  734. public override Stream AcquireLock()
  735. {
  736. if (m_mutex != null)
  737. {
  738. // TODO: add timeout?
  739. m_mutex.WaitOne();
  740. // increment recursive watch
  741. m_recursiveWatch++;
  742. // should always be true (and fast) for FileStream
  743. if (m_stream != null)
  744. {
  745. if (m_stream.CanSeek)
  746. {
  747. m_stream.Seek(0, SeekOrigin.End);
  748. }
  749. }
  750. else
  751. {
  752. // this can happen when the file appender cannot open a file for writing
  753. }
  754. }
  755. else
  756. {
  757. CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to acquire lock! From here on things will be dangerous!");
  758. }
  759. return m_stream;
  760. }
  761. /// <summary>
  762. /// Releases the lock and allows others to acquire a lock.
  763. /// </summary>
  764. public override void ReleaseLock()
  765. {
  766. if (m_mutex != null)
  767. {
  768. if (m_recursiveWatch > 0)
  769. {
  770. m_recursiveWatch--;
  771. m_mutex.ReleaseMutex();
  772. }
  773. }
  774. else
  775. {
  776. CurrentAppender.ErrorHandler.Error("Programming error, no mutex available to release the lock!");
  777. }
  778. }
  779. /// <summary>
  780. /// Initializes all resources used by this locking model.
  781. /// </summary>
  782. public override void ActivateOptions()
  783. {
  784. if (m_mutex == null)
  785. {
  786. string mutexFriendlyFilename = CurrentAppender.File
  787. .Replace("\\", "_")
  788. .Replace(":", "_")
  789. .Replace("/", "_");
  790. m_mutex = new Mutex(false, mutexFriendlyFilename);
  791. }
  792. else
  793. {
  794. CurrentAppender.ErrorHandler.Error("Programming error, mutex already initialized!");
  795. }
  796. }
  797. /// <summary>
  798. /// Disposes all resources that were initialized by this locking model.
  799. /// </summary>
  800. public override void OnClose()
  801. {
  802. if (m_mutex != null)
  803. {
  804. #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
  805. m_mutex.Dispose();
  806. #else
  807. m_mutex.Close();
  808. #endif
  809. m_mutex = null;
  810. }
  811. else
  812. {
  813. CurrentAppender.ErrorHandler.Error("Programming error, mutex not initialized!");
  814. }
  815. }
  816. }
  817. #endif
  818. #endregion Locking Models
  819. #region Public Instance Constructors
  820. /// <summary>
  821. /// Default constructor
  822. /// </summary>
  823. /// <remarks>
  824. /// <para>
  825. /// Default constructor
  826. /// </para>
  827. /// </remarks>
  828. public FileAppender()
  829. {
  830. }
  831. /// <summary>
  832. /// Construct a new appender using the layout, file and append mode.
  833. /// </summary>
  834. /// <param name="layout">the layout to use with this appender</param>
  835. /// <param name="filename">the full path to the file to write to</param>
  836. /// <param name="append">flag to indicate if the file should be appended to</param>
  837. /// <remarks>
  838. /// <para>
  839. /// Obsolete constructor.
  840. /// </para>
  841. /// </remarks>
  842. [Obsolete("Instead use the default constructor and set the Layout, File & AppendToFile properties")]
  843. public FileAppender(ILayout layout, string filename, bool append)
  844. {
  845. Layout = layout;
  846. File = filename;
  847. AppendToFile = append;
  848. ActivateOptions();
  849. }
  850. /// <summary>
  851. /// Construct a new appender using the layout and file specified.
  852. /// The file will be appended to.
  853. /// </summary>
  854. /// <param name="layout">the layout to use with this appender</param>
  855. /// <param name="filename">the full path to the file to write to</param>
  856. /// <remarks>
  857. /// <para>
  858. /// Obsolete constructor.
  859. /// </para>
  860. /// </remarks>
  861. [Obsolete("Instead use the default constructor and set the Layout & File properties")]
  862. public FileAppender(ILayout layout, string filename)
  863. : this(layout, filename, true)
  864. {
  865. }
  866. #endregion Public Instance Constructors
  867. #region Public Instance Properties
  868. /// <summary>
  869. /// Gets or sets the path to the file that logging will be written to.
  870. /// </summary>
  871. /// <value>
  872. /// The path to the file that logging will be written to.
  873. /// </value>
  874. /// <remarks>
  875. /// <para>
  876. /// If the path is relative it is taken as relative from
  877. /// the application base directory.
  878. /// </para>
  879. /// </remarks>
  880. virtual public string File
  881. {
  882. get { return m_fileName; }
  883. set { m_fileName = value; }
  884. }
  885. /// <summary>
  886. /// Gets or sets a flag that indicates whether the file should be
  887. /// appended to or overwritten.
  888. /// </summary>
  889. /// <value>
  890. /// Indicates whether the file should be appended to or overwritten.
  891. /// </value>
  892. /// <remarks>
  893. /// <para>
  894. /// If the value is set to false then the file will be overwritten, if
  895. /// it is set to true then the file will be appended to.
  896. /// </para>
  897. /// The default value is true.
  898. /// </remarks>
  899. public bool AppendToFile
  900. {
  901. get { return m_appendToFile; }
  902. set { m_appendToFile = value; }
  903. }
  904. /// <summary>
  905. /// Gets or sets <see cref="Encoding"/> used to write to the file.
  906. /// </summary>
  907. /// <value>
  908. /// The <see cref="Encoding"/> used to write to the file.
  909. /// </value>
  910. /// <remarks>
  911. /// <para>
  912. /// The default encoding set is <see cref="System.Text.Encoding.Default"/>
  913. /// which is the encoding for the system's current ANSI code page.
  914. /// </para>
  915. /// </remarks>
  916. public Encoding Encoding
  917. {
  918. get { return m_encoding; }
  919. set { m_encoding = value; }
  920. }
  921. /// <summary>
  922. /// Gets or sets the <see cref="SecurityContext"/> used to write to the file.
  923. /// </summary>
  924. /// <value>
  925. /// The <see cref="SecurityContext"/> used to write to the file.
  926. /// </value>
  927. /// <remarks>
  928. /// <para>
  929. /// Unless a <see cref="SecurityContext"/> specified here for this appender
  930. /// the <see cref="SecurityContextProvider.DefaultProvider"/> is queried for the
  931. /// security context to use. The default behavior is to use the security context
  932. /// of the current thread.
  933. /// </para>
  934. /// </remarks>
  935. public SecurityContext SecurityContext
  936. {
  937. get { return m_securityContext; }
  938. set { m_securityContext = value; }
  939. }
  940. #if NETCF
  941. /// <summary>
  942. /// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
  943. /// </summary>
  944. /// <value>
  945. /// The <see cref="FileAppender.LockingModel"/> used to lock the file.
  946. /// </value>
  947. /// <remarks>
  948. /// <para>
  949. /// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
  950. /// </para>
  951. /// <para>
  952. /// There are two built in locking models, <see cref="FileAppender.ExclusiveLock"/> and <see cref="FileAppender.MinimalLock"/>.
  953. /// The first locks the file from the start of logging to the end, the
  954. /// second locks only for the minimal amount of time when logging each message
  955. /// and the last synchronizes processes using a named system wide Mutex.
  956. /// </para>
  957. /// <para>
  958. /// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
  959. /// </para>
  960. /// </remarks>
  961. #else
  962. /// <summary>
  963. /// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
  964. /// </summary>
  965. /// <value>
  966. /// The <see cref="FileAppender.LockingModel"/> used to lock the file.
  967. /// </value>
  968. /// <remarks>
  969. /// <para>
  970. /// Gets or sets the <see cref="FileAppender.LockingModel"/> used to handle locking of the file.
  971. /// </para>
  972. /// <para>
  973. /// There are three built in locking models, <see cref="FileAppender.ExclusiveLock"/>, <see cref="FileAppender.MinimalLock"/> and <see cref="FileAppender.InterProcessLock"/> .
  974. /// The first locks the file from the start of logging to the end, the
  975. /// second locks only for the minimal amount of time when logging each message
  976. /// and the last synchronizes processes using a named system wide Mutex.
  977. /// </para>
  978. /// <para>
  979. /// The default locking model is the <see cref="FileAppender.ExclusiveLock"/>.
  980. /// </para>
  981. /// </remarks>
  982. #endif
  983. public FileAppender.LockingModelBase LockingModel
  984. {
  985. get { return m_lockingModel; }
  986. set { m_lockingModel = value; }
  987. }
  988. #endregion Public Instance Properties
  989. #region Override implementation of AppenderSkeleton
  990. /// <summary>
  991. /// Activate the options on the file appender.
  992. /// </summary>
  993. /// <remarks>
  994. /// <para>
  995. /// This is part of the <see cref="IOptionHandler"/> delayed object
  996. /// activation scheme. The <see cref="ActivateOptions"/> method must
  997. /// be called on this object after the configuration properties have
  998. /// been set. Until <see cref="ActivateOptions"/> is called this
  999. /// object is in an undefined state and must not be used.
  1000. /// </para>
  1001. /// <para>
  1002. /// If any of the configuration properties are modified then
  1003. /// <see cref="ActivateOptions"/> must be called again.
  1004. /// </para>
  1005. /// <para>
  1006. /// This will cause the file to be opened.
  1007. /// </para>
  1008. /// </remarks>
  1009. override public void ActivateOptions()
  1010. {
  1011. base.ActivateOptions();
  1012. if (m_securityContext == null)
  1013. {
  1014. m_securityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  1015. }
  1016. if (m_lockingModel == null)
  1017. {
  1018. m_lockingModel = new FileAppender.ExclusiveLock();
  1019. }
  1020. m_lockingModel.CurrentAppender = this;
  1021. m_lockingModel.ActivateOptions();
  1022. if (m_fileName != null)
  1023. {
  1024. using (SecurityContext.Impersonate(this))
  1025. {
  1026. m_fileName = ConvertToFullPath(m_fileName.Trim());
  1027. }
  1028. SafeOpenFile(m_fileName, m_appendToFile);
  1029. }
  1030. else
  1031. {
  1032. LogLog.Warn(declaringType, "FileAppender: File option not set for appender [" + Name + "].");
  1033. LogLog.Warn(declaringType, "FileAppender: Are you using FileAppender instead of ConsoleAppender?");
  1034. }
  1035. }
  1036. #endregion Override implementation of AppenderSkeleton
  1037. #region Override implementation of TextWriterAppender
  1038. /// <summary>
  1039. /// Closes any previously opened file and calls the parent's <see cref="TextWriterAppender.Reset"/>.
  1040. /// </summary>
  1041. /// <remarks>
  1042. /// <para>
  1043. /// Resets the filename and the file stream.
  1044. /// </para>
  1045. /// </remarks>
  1046. override protected void Reset()
  1047. {
  1048. base.Reset();
  1049. m_fileName = null;
  1050. }
  1051. /// <summary>
  1052. /// Close this appender instance. The underlying stream or writer is also closed.
  1053. /// </summary>
  1054. override protected void OnClose()
  1055. {
  1056. base.OnClose();
  1057. m_lockingModel.OnClose();
  1058. }
  1059. /// <summary>
  1060. /// Called to initialize the file writer
  1061. /// </summary>
  1062. /// <remarks>
  1063. /// <para>
  1064. /// Will be called for each logged message until the file is
  1065. /// successfully opened.
  1066. /// </para>
  1067. /// </remarks>
  1068. override protected void PrepareWriter()
  1069. {
  1070. SafeOpenFile(m_fileName, m_appendToFile);
  1071. }
  1072. /// <summary>
  1073. /// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent)"/>
  1074. /// method.
  1075. /// </summary>
  1076. /// <param name="loggingEvent">The event to log.</param>
  1077. /// <remarks>
  1078. /// <para>
  1079. /// Writes a log statement to the output stream if the output stream exists
  1080. /// and is writable.
  1081. /// </para>
  1082. /// <para>
  1083. /// The format of the output will depend on the appender's layout.
  1084. /// </para>
  1085. /// </remarks>
  1086. override protected void Append(LoggingEvent loggingEvent)
  1087. {
  1088. if (m_stream.AcquireLock())
  1089. {
  1090. try
  1091. {
  1092. base.Append(loggingEvent);
  1093. }
  1094. finally
  1095. {
  1096. m_stream.ReleaseLock();
  1097. }
  1098. }
  1099. }
  1100. /// <summary>
  1101. /// This method is called by the <see cref="M:AppenderSkeleton.DoAppend(LoggingEvent[])"/>
  1102. /// method.
  1103. /// </summary>
  1104. /// <param name="loggingEvents">The array of events to log.</param>
  1105. /// <remarks>
  1106. /// <para>
  1107. /// Acquires the output file locks once before writing all the events to
  1108. /// the stream.
  1109. /// </para>
  1110. /// </remarks>
  1111. override protected void Append(LoggingEvent[] loggingEvents)
  1112. {
  1113. if (m_stream.AcquireLock())
  1114. {
  1115. try
  1116. {
  1117. base.Append(loggingEvents);
  1118. }
  1119. finally
  1120. {
  1121. m_stream.ReleaseLock();
  1122. }
  1123. }
  1124. }
  1125. /// <summary>
  1126. /// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
  1127. /// </summary>
  1128. /// <remarks>
  1129. /// <para>
  1130. /// Writes a footer as produced by the embedded layout's <see cref="ILayout.Footer"/> property.
  1131. /// </para>
  1132. /// </remarks>
  1133. protected override void WriteFooter()
  1134. {
  1135. if (m_stream != null)
  1136. {
  1137. //WriteFooter can be called even before a file is opened
  1138. m_stream.AcquireLock();
  1139. try
  1140. {
  1141. base.WriteFooter();
  1142. }
  1143. finally
  1144. {
  1145. m_stream.ReleaseLock();
  1146. }
  1147. }
  1148. }
  1149. /// <summary>
  1150. /// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
  1151. /// </summary>
  1152. /// <remarks>
  1153. /// <para>
  1154. /// Writes a header produced by the embedded layout's <see cref="ILayout.Header"/> property.
  1155. /// </para>
  1156. /// </remarks>
  1157. protected override void WriteHeader()
  1158. {
  1159. if (m_stream != null)
  1160. {
  1161. if (m_stream.AcquireLock())
  1162. {
  1163. try
  1164. {
  1165. base.WriteHeader();
  1166. }
  1167. finally
  1168. {
  1169. m_stream.ReleaseLock();
  1170. }
  1171. }
  1172. }
  1173. }
  1174. /// <summary>
  1175. /// Closes the underlying <see cref="TextWriter"/>.
  1176. /// </summary>
  1177. /// <remarks>
  1178. /// <para>
  1179. /// Closes the underlying <see cref="TextWriter"/>.
  1180. /// </para>
  1181. /// </remarks>
  1182. protected override void CloseWriter()
  1183. {
  1184. if (m_stream != null)
  1185. {
  1186. m_stream.AcquireLock();
  1187. try
  1188. {
  1189. base.CloseWriter();
  1190. }
  1191. finally
  1192. {
  1193. m_stream.ReleaseLock();
  1194. }
  1195. }
  1196. }
  1197. #endregion Override implementation of TextWriterAppender
  1198. #region Public Instance Methods
  1199. /// <summary>
  1200. /// Closes the previously opened file.
  1201. /// </summary>
  1202. /// <remarks>
  1203. /// <para>
  1204. /// Writes the <see cref="ILayout.Footer"/> to the file and then
  1205. /// closes the file.
  1206. /// </para>
  1207. /// </remarks>
  1208. protected void CloseFile()
  1209. {
  1210. WriteFooterAndCloseWriter();
  1211. }
  1212. #endregion Public Instance Methods
  1213. #region Protected Instance Methods
  1214. /// <summary>
  1215. /// Sets and <i>opens</i> the file where the log output will go. The specified file must be writable.
  1216. /// </summary>
  1217. /// <param name="fileName">The path to the log file. Must be a fully qualified path.</param>
  1218. /// <param name="append">If true will append to fileName. Otherwise will truncate fileName</param>
  1219. /// <remarks>
  1220. /// <para>
  1221. /// Calls <see cref="OpenFile"/> but guarantees not to throw an exception.
  1222. /// Errors are passed to the <see cref="TextWriterAppender.ErrorHandler"/>.
  1223. /// </para>
  1224. /// </remarks>
  1225. virtual protected void SafeOpenFile(string fileName, bool append)
  1226. {
  1227. try
  1228. {
  1229. OpenFile(fileName, append);
  1230. }
  1231. catch (Exception e)
  1232. {
  1233. ErrorHandler.Error("OpenFile(" + fileName + "," + append + ") call failed.", e, ErrorCode.FileOpenFailure);
  1234. }
  1235. }
  1236. /// <summary>
  1237. /// Sets and <i>opens</i> the file where the log output will go. The specified file must be writable.
  1238. /// </summary>
  1239. /// <param name="fileName">The path to the log file. Must be a fully qualified path.</param>
  1240. /// <param name="append">If true will append to fileName. Otherwise will truncate fileName</param>
  1241. /// <remarks>
  1242. /// <para>
  1243. /// If there was already an opened file, then the previous file
  1244. /// is closed first.
  1245. /// </para>
  1246. /// <para>
  1247. /// This method will ensure that the directory structure
  1248. /// for the <paramref name="fileName"/> specified exists.
  1249. /// </para>
  1250. /// </remarks>
  1251. virtual protected void OpenFile(string fileName, bool append)
  1252. {
  1253. if (LogLog.IsErrorEnabled)
  1254. {
  1255. // Internal check that the fileName passed in is a rooted path
  1256. bool isPathRooted = false;
  1257. using (SecurityContext.Impersonate(this))
  1258. {
  1259. isPathRooted = Path.IsPathRooted(fileName);
  1260. }
  1261. if (!isPathRooted)
  1262. {
  1263. LogLog.Error(declaringType, "INTERNAL ERROR. OpenFile(" + fileName + "): File name is not fully qualified.");
  1264. }
  1265. }
  1266. lock (this)
  1267. {
  1268. Reset();
  1269. LogLog.Debug(declaringType, "Opening file for writing [" + fileName + "] append [" + append + "]");
  1270. // Save these for later, allowing retries if file open fails
  1271. m_fileName = fileName;
  1272. m_appendToFile = append;
  1273. LockingModel.CurrentAppender = this;
  1274. LockingModel.OpenFile(fileName, append, m_encoding);
  1275. m_stream = new LockingStream(LockingModel);
  1276. if (m_stream != null)
  1277. {
  1278. m_stream.AcquireLock();
  1279. try
  1280. {
  1281. SetQWForFiles(m_stream);
  1282. }
  1283. finally
  1284. {
  1285. m_stream.ReleaseLock();
  1286. }
  1287. }
  1288. WriteHeader();
  1289. }
  1290. }
  1291. /// <summary>
  1292. /// Sets the quiet writer used for file output
  1293. /// </summary>
  1294. /// <param name="fileStream">the file stream that has been opened for writing</param>
  1295. /// <remarks>
  1296. /// <para>
  1297. /// This implementation of <see cref="M:SetQWForFiles(Stream)"/> creates a <see cref="StreamWriter"/>
  1298. /// over the <paramref name="fileStream"/> and passes it to the
  1299. /// <see cref="M:SetQWForFiles(TextWriter)"/> method.
  1300. /// </para>
  1301. /// <para>
  1302. /// This method can be overridden by sub classes that want to wrap the
  1303. /// <see cref="Stream"/> in some way, for example to encrypt the output
  1304. /// data using a <c>System.Security.Cryptography.CryptoStream</c>.
  1305. /// </para>
  1306. /// </remarks>
  1307. virtual protected void SetQWForFiles(Stream fileStream)
  1308. {
  1309. SetQWForFiles(new StreamWriter(fileStream, m_encoding));
  1310. }
  1311. /// <summary>
  1312. /// Sets the quiet writer being used.
  1313. /// </summary>
  1314. /// <param name="writer">the writer over the file stream that has been opened for writing</param>
  1315. /// <remarks>
  1316. /// <para>
  1317. /// This method can be overridden by sub classes that want to
  1318. /// wrap the <see cref="TextWriter"/> in some way.
  1319. /// </para>
  1320. /// </remarks>
  1321. virtual protected void SetQWForFiles(TextWriter writer)
  1322. {
  1323. QuietWriter = new QuietTextWriter(writer, ErrorHandler);
  1324. }
  1325. #endregion Protected Instance Methods
  1326. #region Protected Static Methods
  1327. /// <summary>
  1328. /// Convert a path into a fully qualified path.
  1329. /// </summary>
  1330. /// <param name="path">The path to convert.</param>
  1331. /// <returns>The fully qualified path.</returns>
  1332. /// <remarks>
  1333. /// <para>
  1334. /// Converts the path specified to a fully
  1335. /// qualified path. If the path is relative it is
  1336. /// taken as relative from the application base
  1337. /// directory.
  1338. /// </para>
  1339. /// </remarks>
  1340. protected static string ConvertToFullPath(string path)
  1341. {
  1342. return SystemInfo.ConvertToFullPath(path);
  1343. }
  1344. #endregion Protected Static Methods
  1345. #region Private Instance Fields
  1346. /// <summary>
  1347. /// Flag to indicate if we should append to the file
  1348. /// or overwrite the file. The default is to append.
  1349. /// </summary>
  1350. private bool m_appendToFile = true;
  1351. /// <summary>
  1352. /// The name of the log file.
  1353. /// </summary>
  1354. private string m_fileName = null;
  1355. /// <summary>
  1356. /// The encoding to use for the file stream.
  1357. /// </summary>
  1358. private Encoding m_encoding = Encoding.GetEncoding(0);
  1359. /// <summary>
  1360. /// The security context to use for privileged calls
  1361. /// </summary>
  1362. private SecurityContext m_securityContext;
  1363. /// <summary>
  1364. /// The stream to log to. Has added locking semantics
  1365. /// </summary>
  1366. private FileAppender.LockingStream m_stream = null;
  1367. /// <summary>
  1368. /// The locking model to use
  1369. /// </summary>
  1370. private FileAppender.LockingModelBase m_lockingModel = new FileAppender.ExclusiveLock();
  1371. #endregion Private Instance Fields
  1372. #region Private Static Fields
  1373. /// <summary>
  1374. /// The fully qualified type of the FileAppender class.
  1375. /// </summary>
  1376. /// <remarks>
  1377. /// Used by the internal logger to record the Type of the
  1378. /// log message.
  1379. /// </remarks>
  1380. private readonly static Type declaringType = typeof(FileAppender);
  1381. #endregion Private Static Fields
  1382. }
  1383. }