Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9cfd3de

Browse files
committed
Support ILoggingFailureListener; seals PeriodicFlushToDiskSink, so technically a breaking change
1 parent5697cc1 commit9cfd3de

13 files changed

+226
-35
lines changed

‎src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,17 +549,26 @@ static LoggerConfiguration ConfigureFile(
549549
}
550550
catch(Exceptionex)
551551
{
552-
SelfLog.WriteLine("Unable to open file sink for {0}: {1}",path,ex);
552+
// No logging failure listener can be configured here; in future we might allow for a static
553+
// default listener, but in the meantime this improves `SelfLog` usefulness and consistency.
554+
SelfLog.FailureListener.OnLoggingFailed(
555+
typeof(FileLoggerConfigurationExtensions),
556+
LoggingFailureKind.Final,
557+
$"unable to open file sink for{path}",
558+
events:null,
559+
ex);
553560

554561
if(propagateExceptions)
555562
throw;
556563

557-
returnaddSink(newNullSink(),LevelAlias.Maximum,null);
564+
returnaddSink(newFailedSink(),restrictedToMinimumLevel,levelSwitch);
558565
}
559566

560567
if(flushToDiskInterval.HasValue)
561568
{
562569
#pragma warning disable618
570+
// `LoggerSinkConfiguration.Wrap()` is not used here because the target sink is expected
571+
// to support `ILogEventSink`.
563572
sink=newPeriodicFlushToDiskSink(sink,flushToDiskInterval.Value);
564573
#pragma warning restore618
565574
}

‎src/Serilog.Sinks.File/Serilog.Sinks.File.csproj‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Description>Write Serilog events to text files in plain or JSON format.</Description>
5-
<VersionPrefix>6.0.1</VersionPrefix>
5+
<VersionPrefix>7.0.0</VersionPrefix>
66
<Authors>Serilog Contributors</Authors>
77
<!-- .NET Framework version targeting is frozen at these two TFMs.-->
88
<TargetFrameworksCondition=" '$(OS)' == 'Windows_NT'">net471;net462</TargetFrameworks>
@@ -26,7 +26,7 @@
2626
</PropertyGroup>
2727

2828
<ItemGroup>
29-
<PackageReferenceInclude="Serilog"Version="4.0.0" />
29+
<PackageReferenceInclude="Serilog"Version="4.2.0" />
3030
<PackageReferenceInclude="Nullable"Version="1.3.1"PrivateAssets="All" />
3131
</ItemGroup>
3232

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright © Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
usingSerilog.Core;
16+
usingSerilog.Debugging;
17+
usingSerilog.Events;
18+
19+
namespaceSerilog.Sinks.File;
20+
21+
sealedclassFailedSink:ILogEventSink,ISetLoggingFailureListener
22+
{
23+
ILoggingFailureListener_failureListener=SelfLog.FailureListener;
24+
25+
publicvoidEmit(LogEventlogEvent)
26+
{
27+
_failureListener.OnLoggingFailed(this,LoggingFailureKind.Final,"the sink could not be initialized",[logEvent],exception:null);
28+
}
29+
30+
publicvoidSetFailureListener(ILoggingFailureListenerfailureListener)
31+
{
32+
_failureListener=failureListener??thrownewArgumentNullException(nameof(failureListener));
33+
}
34+
}

‎src/Serilog.Sinks.File/Sinks/File/FileSink.cs‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// limitations under the License.
1414

1515
usingSystem.Text;
16+
usingSerilog.Core;
17+
usingSerilog.Debugging;
1618
usingSerilog.Events;
1719
usingSerilog.Formatting;
1820

@@ -21,7 +23,7 @@ namespace Serilog.Sinks.File;
2123
/// <summary>
2224
/// Write log events to a disk file.
2325
/// </summary>
24-
publicsealedclassFileSink:IFileSink,IDisposable
26+
publicsealedclassFileSink:IFileSink,IDisposable,ISetLoggingFailureListener
2527
{
2628
readonlyTextWriter_output;
2729
readonlyFileStream_underlyingStream;
@@ -31,6 +33,8 @@ public sealed class FileSink : IFileSink, IDisposable
3133
readonlyobject_syncRoot=new();
3234
readonlyWriteCountingStream?_countingStreamWrapper;
3335

36+
ILoggingFailureListener_failureListener=SelfLog.FailureListener;
37+
3438
/// <summary>Construct a <see cref="FileSink"/>.</summary>
3539
/// <param name="path">Path to the file.</param>
3640
/// <param name="textFormatter">Formatter used to convert log events to text.</param>
@@ -98,7 +102,7 @@ internal FileSink(
98102
}
99103
catch
100104
{
101-
outputStream?.Dispose();
105+
outputStream.Dispose();
102106
throw;
103107
}
104108
}
@@ -132,7 +136,16 @@ bool IFileSink.EmitOrOverflow(LogEvent logEvent)
132136
/// <exception cref="ArgumentNullException">When <paramref name="logEvent"/> is <code>null</code></exception>
133137
publicvoidEmit(LogEventlogEvent)
134138
{
135-
((IFileSink)this).EmitOrOverflow(logEvent);
139+
if(!((IFileSink)this).EmitOrOverflow(logEvent))
140+
{
141+
// Support fallback chains without the overhead of throwing an exception.
142+
_failureListener.OnLoggingFailed(
143+
this,
144+
LoggingFailureKind.Permanent,
145+
"the log file size limit has been reached and no rolling behavior was specified",
146+
[logEvent],
147+
exception:null);
148+
}
136149
}
137150

138151
/// <inheritdoc />
@@ -153,4 +166,9 @@ public void FlushToDisk()
153166
_underlyingStream.Flush(true);
154167
}
155168
}
169+
170+
voidISetLoggingFailureListener.SetFailureListener(ILoggingFailureListenerfailureListener)
171+
{
172+
_failureListener=failureListener??thrownewArgumentNullException(nameof(failureListener));
173+
}
156174
}

‎src/Serilog.Sinks.File/Sinks/File/PeriodicFlushToDiskSink.cs‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ namespace Serilog.Sinks.File;
2222
/// A sink wrapper that periodically flushes the wrapped sink to disk.
2323
/// </summary>
2424
[Obsolete("This type will be removed from the public API in a future version; use `WriteTo.File(flushToDiskInterval:)` instead.")]
25-
publicclassPeriodicFlushToDiskSink:ILogEventSink,IDisposable
25+
publicsealedclassPeriodicFlushToDiskSink:ILogEventSink,IDisposable,ISetLoggingFailureListener
2626
{
2727
readonlyILogEventSink_sink;
2828
readonlyTimer_timer;
2929
int_flushRequired;
3030

31+
ILoggingFailureListener_failureListener=SelfLog.FailureListener;
32+
3133
/// <summary>
3234
/// Construct a <see cref="PeriodicFlushToDiskSink"/> that wraps
3335
/// <paramref name="sink"/> and flushes it at the specified <paramref name="flushInterval"/>.
@@ -46,7 +48,17 @@ public PeriodicFlushToDiskSink(ILogEventSink sink, TimeSpan flushInterval)
4648
else
4749
{
4850
_timer=newTimer(_=>{},null,Timeout.InfiniteTimeSpan,Timeout.InfiniteTimeSpan);
49-
SelfLog.WriteLine("{0} configured to flush {1}, but {2} not implemented",typeof(PeriodicFlushToDiskSink),sink,nameof(IFlushableFileSink));
51+
52+
// May be an opportunity to improve the failure listener API for these cases - the failure
53+
// is important, but not exactly `Final`.
54+
SelfLog.FailureListener.OnLoggingFailed(
55+
// Class must be sealed in order for this to be safe - `this` may be partially constructed
56+
// otherwise.
57+
this,
58+
LoggingFailureKind.Final,
59+
$"configured to flush{sink}, but{nameof(IFlushableFileSink)} not implemented",
60+
events:null,
61+
exception:null);
5062
}
5163
}
5264

@@ -77,7 +89,21 @@ void FlushToDisk(IFlushableFileSink flushable)
7789
}
7890
catch(Exceptionex)
7991
{
80-
SelfLog.WriteLine("{0} could not flush the underlying sink to disk: {1}",typeof(PeriodicFlushToDiskSink),ex);
92+
_failureListener.OnLoggingFailed(
93+
this,
94+
LoggingFailureKind.Temporary,
95+
"could not flush the underlying file to disk",
96+
events:null,
97+
ex);
98+
}
99+
}
100+
101+
voidISetLoggingFailureListener.SetFailureListener(ILoggingFailureListenerfailureListener)
102+
{
103+
_failureListener=failureListener??thrownewArgumentNullException(nameof(failureListener));
104+
if(_sinkisISetLoggingFailureListenersetLoggingFailureListener)
105+
{
106+
setLoggingFailureListener.SetFailureListener(failureListener);
81107
}
82108
}
83109
}

‎src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
namespaceSerilog.Sinks.File;
2222

23-
sealedclassRollingFileSink:ILogEventSink,IFlushableFileSink,IDisposable
23+
sealedclassRollingFileSink:ILogEventSink,IFlushableFileSink,IDisposable,ISetLoggingFailureListener
2424
{
2525
readonlyPathRoller_roller;
2626
readonlyITextFormatter_textFormatter;
@@ -33,6 +33,8 @@ sealed class RollingFileSink : ILogEventSink, IFlushableFileSink, IDisposable
3333
readonlybool_rollOnFileSizeLimit;
3434
readonlyFileLifecycleHooks?_hooks;
3535

36+
ILoggingFailureListener_failureListener=SelfLog.FailureListener;
37+
3638
readonlyobject_syncRoot=new();
3739
bool_isDisposed;
3840
DateTime?_nextCheckpoint;
@@ -72,6 +74,7 @@ public void Emit(LogEvent logEvent)
7274
{
7375
if(logEvent==null)thrownewArgumentNullException(nameof(logEvent));
7476

77+
boolfailed;
7578
lock(_syncRoot)
7679
{
7780
if(_isDisposed)thrownewObjectDisposedException("The log file has been disposed.");
@@ -84,12 +87,18 @@ public void Emit(LogEvent logEvent)
8487
AlignCurrentFileTo(now,nextSequence:true);
8588
}
8689

87-
/* TODO: We REALLY should add this to avoid stuff become missing undetected.
88-
if (_currentFile == null)
89-
{
90-
SelfLog.WriteLine("Log event {0} was lost since it was not possible to open the file or create a new one.", logEvent.RenderMessage());
91-
}
92-
*/
90+
failed=_currentFile==null;
91+
}
92+
93+
if(failed)
94+
{
95+
// Support fallback chains without the overhead of throwing an exception.
96+
_failureListener.OnLoggingFailed(
97+
this,
98+
LoggingFailureKind.Permanent,
99+
"the target file could not be opened or created",
100+
[logEvent],
101+
exception:null);
93102
}
94103
}
95104

@@ -170,14 +179,22 @@ void OpenFile(DateTime now, int? minSequence = null)
170179
newFileSink(path,_textFormatter,_fileSizeLimitBytes,_encoding,_buffered,_hooks);
171180

172181
_currentFileSequence=sequence;
182+
183+
if(_currentFileisISetLoggingFailureListenersetLoggingFailureListener)
184+
{
185+
setLoggingFailureListener.SetFailureListener(_failureListener);
186+
}
173187
}
174188
catch(IOExceptionex)
175189
{
176190
if(IOErrors.IsLockedFile(ex))
177191
{
178-
SelfLog.WriteLine(
179-
"File target {0} was locked, attempting to open next in sequence (attempt {1})",path,
180-
attempt+1);
192+
_failureListener.OnLoggingFailed(
193+
this,
194+
LoggingFailureKind.Temporary,
195+
$"file target{path} was locked, attempting to open next in sequence (attempt{attempt+1})",
196+
events:null,
197+
exception:null);
181198
sequence=(sequence??0)+1;
182199
continue;
183200
}
@@ -216,7 +233,7 @@ void ApplyRetentionPolicy(string currentFilePath, DateTime now)
216233
// ReSharper disable once ConvertClosureToMethodGroup
217234
varpotentialMatches=Directory.GetFiles(_roller.LogFileDirectory,_roller.DirectorySearchPattern)
218235
.Select(f=>Path.GetFileName(f))
219-
.Union(new[]{currentFileName});
236+
.Union([currentFileName]);
220237

221238
varnewestFirst=_roller
222239
.SelectMatches(potentialMatches)
@@ -239,7 +256,12 @@ void ApplyRetentionPolicy(string currentFilePath, DateTime now)
239256
}
240257
catch(Exceptionex)
241258
{
242-
SelfLog.WriteLine("Error {0} while processing obsolete log file {1}",ex,fullPath);
259+
_failureListener.OnLoggingFailed(
260+
this,
261+
LoggingFailureKind.Temporary,
262+
$"error while processing obsolete log file{fullPath}",
263+
events:null,
264+
ex);
243265
}
244266
}
245267
}
@@ -286,4 +308,9 @@ public void FlushToDisk()
286308
_currentFile?.FlushToDisk();
287309
}
288310
}
311+
312+
publicvoidSetFailureListener(ILoggingFailureListenerfailureListener)
313+
{
314+
_failureListener=failureListener??thrownewArgumentNullException(nameof(failureListener));
315+
}
289316
}

‎src/Serilog.Sinks.File/Sinks/File/SharedFileSink.AtomicAppend.cs‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
usingSystem.Security.AccessControl;
1818
usingSystem.Text;
19+
usingSerilog.Core;
20+
usingSerilog.Debugging;
1921
usingSerilog.Events;
2022
usingSerilog.Formatting;
2123

@@ -25,7 +27,7 @@ namespace Serilog.Sinks.File;
2527
/// Write log events to a disk file.
2628
/// </summary>
2729
[Obsolete("This type will be removed from the public API in a future version; use `WriteTo.File(shared: true)` instead.")]
28-
publicsealedclassSharedFileSink:IFileSink,IDisposable
30+
publicsealedclassSharedFileSink:IFileSink,IDisposable,ISetLoggingFailureListener
2931
{
3032
readonlyMemoryStream_writeBuffer;
3133
readonlystring_path;
@@ -34,6 +36,8 @@ public sealed class SharedFileSink : IFileSink, IDisposable
3436
readonlylong?_fileSizeLimitBytes;
3537
readonlyobject_syncRoot=new();
3638

39+
ILoggingFailureListener_failureListener=SelfLog.FailureListener;
40+
3741
// The stream is reopened with a larger buffer if atomic writes beyond the current buffer size are needed.
3842
FileStream_fileOutput;
3943
int_fileStreamBufferLength=DefaultFileStreamBufferLength;
@@ -59,7 +63,7 @@ public sealed class SharedFileSink : IFileSink, IDisposable
5963
publicSharedFileSink(stringpath,ITextFormattertextFormatter,long?fileSizeLimitBytes,Encoding?encoding=null)
6064
{
6165
if(fileSizeLimitBytes.HasValue&&fileSizeLimitBytes<1)
62-
thrownewArgumentException("Invalid value provided; file size limit must be at least 1 byte, or null");
66+
thrownewArgumentException("Invalid value provided; file size limit must be at least 1 byte, or null.");
6367

6468
_path=path??thrownewArgumentNullException(nameof(path));
6569
_textFormatter=textFormatter??thrownewArgumentNullException(nameof(textFormatter));
@@ -149,7 +153,16 @@ bool IFileSink.EmitOrOverflow(LogEvent logEvent)
149153
/// <exception cref="ArgumentNullException">When <paramref name="logEvent"/> is <code>null</code></exception>
150154
publicvoidEmit(LogEventlogEvent)
151155
{
152-
((IFileSink)this).EmitOrOverflow(logEvent);
156+
if(!((IFileSink)this).EmitOrOverflow(logEvent))
157+
{
158+
// Support fallback chains without the overhead of throwing an exception.
159+
_failureListener.OnLoggingFailed(
160+
this,
161+
LoggingFailureKind.Permanent,
162+
"the log file size limit has been reached and no rolling behavior was specified",
163+
[logEvent],
164+
exception:null);
165+
}
153166
}
154167

155168
/// <inheritdoc />
@@ -170,6 +183,11 @@ public void FlushToDisk()
170183
_fileOutput.Flush(true);
171184
}
172185
}
186+
187+
voidISetLoggingFailureListener.SetFailureListener(ILoggingFailureListenerfailureListener)
188+
{
189+
_failureListener=failureListener??thrownewArgumentNullException(nameof(failureListener));
190+
}
173191
}
174192

175193
#endif

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp