2021-11-04 18:06:55 +01:00
using System ;
2020-07-23 02:24:18 +02:00
using System.IO ;
namespace ExtremelySimpleLogger {
2020-07-23 02:46:34 +02:00
/// <summary>
/// A <see cref="Sink"/> that writes log output to a file.
/// </summary>
2020-07-23 02:24:18 +02:00
public class FileSink : Sink {
2022-01-17 12:49:50 +01:00
/// <summary>
/// The <see cref="FileInfo"/> that this sink is currently using as its destination.
/// </summary>
public FileInfo CurrentFile {
get {
lock ( this . file )
return this . file ;
}
}
2023-05-08 11:02:25 +02:00
2020-07-23 14:10:43 +02:00
private const int OneGb = 1024 * 1024 * 1024 ;
2020-07-23 13:51:18 +02:00
private readonly FileInfo file ;
2020-07-23 02:24:18 +02:00
private readonly StreamWriter writer ;
2020-07-23 13:51:18 +02:00
private readonly bool reopenOnWrite ;
2020-07-23 02:24:18 +02:00
2020-07-23 02:46:34 +02:00
/// <summary>
/// Creates a new file sink with the given settings.
/// </summary>
/// <param name="file">The full, or relative, path of the file to write to</param>
/// <param name="append">Whether new output should be appended to the old log file</param>
2020-07-23 13:51:18 +02:00
/// <param name="reopenOnWrite">Whether this file sink should reopen the file every time it logs to it. If this is false, the file will be kept open by this sink.</param>
2020-07-23 14:10:43 +02:00
/// <param name="fileSizeLimit">If <paramref name="append"/> is true, this property determines how big the log file has to be (in bytes) before it is deleted on startup. Defaults to 1gb.</param>
public FileSink ( string file , bool append , bool reopenOnWrite = false , int fileSizeLimit = OneGb ) :
2022-01-17 12:49:50 +01:00
this ( new FileInfo ( file ) , append , reopenOnWrite , fileSizeLimit ) { }
2020-07-23 02:24:18 +02:00
2020-07-23 02:46:34 +02:00
/// <summary>
/// Creates a new file sink with the given settings.
/// </summary>
/// <param name="file">The full, or relative, path of the file to write to</param>
/// <param name="append">Whether new output should be appended to the old log file</param>
2020-07-23 13:51:18 +02:00
/// <param name="reopenOnWrite">Whether this file sink should reopen the file every time it logs to it. If this is false, the file will be kept open by this sink.</param>
2020-07-23 14:10:43 +02:00
/// <param name="fileSizeLimit">If <paramref name="append"/> is true, this property determines how big the log file has to be (in bytes) before it is deleted on startup.</param>
public FileSink ( FileInfo file , bool append , bool reopenOnWrite = false , int fileSizeLimit = OneGb ) {
2020-07-23 13:51:18 +02:00
this . reopenOnWrite = reopenOnWrite ;
this . file = file ;
2021-11-04 18:06:55 +01:00
try {
var dir = file . Directory ;
if ( dir ! = null & & ! dir . Exists )
dir . Create ( ) ;
} catch ( Exception e ) {
throw new IOException ( $"Failed to create directory for file sink {file}" , e ) ;
}
2020-07-23 02:24:18 +02:00
2021-11-04 18:06:55 +01:00
try {
if ( file . Exists & & ( ! append | | file . Length > = fileSizeLimit ) )
file . Delete ( ) ;
} catch ( Exception e ) {
throw new IOException ( $"Failed to delete file sink file {file}" , e ) ;
}
2020-07-23 02:24:18 +02:00
2020-07-23 13:51:18 +02:00
if ( ! reopenOnWrite ) {
2021-11-04 18:06:55 +01:00
this . writer = this . Append ( ) ;
2020-07-23 13:51:18 +02:00
this . writer . AutoFlush = true ;
}
2020-07-23 02:24:18 +02:00
}
2020-07-23 02:46:34 +02:00
/// <summary>
2022-10-05 18:13:29 +02:00
/// Logs the given message, which has already been formatted using <see cref="Sink.Formatter"/> or <see cref="Logger.DefaultFormatter"/>.
2020-07-23 02:46:34 +02:00
/// </summary>
2020-07-29 14:23:23 +02:00
/// <param name="logger">The logger that the message was passed to</param>
/// <param name="level">The importance level of this message</param>
2020-07-23 02:46:34 +02:00
/// <param name="s">The message to log</param>
2020-07-29 14:23:23 +02:00
protected override void Log ( Logger logger , LogLevel level , string s ) {
2020-07-29 14:10:49 +02:00
lock ( this . file ) {
if ( this . reopenOnWrite ) {
2021-11-04 18:06:55 +01:00
using ( var w = this . Append ( ) )
2020-07-29 14:10:49 +02:00
w . WriteLine ( s ) ;
} else {
this . writer . WriteLine ( s ) ;
}
2020-07-23 13:51:18 +02:00
}
2020-07-23 02:24:18 +02:00
}
2020-07-23 14:03:25 +02:00
/// <summary>
2020-07-23 14:01:44 +02:00
/// Disposes this sink, freeing all of the resources it uses.
2020-07-23 14:03:25 +02:00
/// </summary>
2020-07-23 14:01:44 +02:00
public override void Dispose ( ) {
base . Dispose ( ) ;
2020-07-29 14:10:49 +02:00
lock ( this . file ) {
if ( ! this . reopenOnWrite )
this . writer . Dispose ( ) ;
}
2020-07-23 14:01:44 +02:00
}
2021-11-04 18:06:55 +01:00
private StreamWriter Append ( ) {
try {
2023-05-08 11:02:25 +02:00
return new StreamWriter ( this . file . Open ( FileMode . Append , FileAccess . Write , FileShare . ReadWrite ) ) ;
2021-11-04 18:06:55 +01:00
} catch ( Exception e ) {
throw new IOException ( $"Failed to append to file sink {this.file}" , e ) ;
}
}
2020-07-23 02:24:18 +02:00
}
}