@@ -26,6 +26,7 @@ public class FlexConsumptionMetricsPublisher : IMetricsPublisher, IDisposable
26
26
private readonly IHostMetricsProvider _metricsProvider ;
27
27
private readonly object _lock = new object ( ) ;
28
28
private readonly IFileSystem _fileSystem ;
29
+ private readonly LegionMetricsFileManager _metricsFileManager ;
29
30
30
31
private Timer _metricsPublisherTimer ;
31
32
private bool _started = false ;
@@ -44,6 +45,7 @@ public FlexConsumptionMetricsPublisher(IEnvironment environment, IOptionsMonitor
44
45
_options = options ? . Value ?? throw new ArgumentNullException ( nameof ( options ) ) ;
45
46
_logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
46
47
_fileSystem = fileSystem ?? new FileSystem ( ) ;
48
+ _metricsFileManager = new LegionMetricsFileManager ( _options . MetricsFilePath , _fileSystem , _logger , _options . MaxFileCount ) ;
47
49
_metricsProvider = metricsProvider ?? throw new ArgumentNullException ( nameof ( metricsProvider ) ) ;
48
50
49
51
if ( _standbyOptions . CurrentValue . InStandbyMode )
@@ -66,13 +68,13 @@ public FlexConsumptionMetricsPublisher(IEnvironment environment, IOptionsMonitor
66
68
67
69
internal bool IsAlwaysReady { get ; set ; }
68
70
69
- internal string MetricsFilePath { get ; set ; }
71
+ internal LegionMetricsFileManager MetricsFileManager => _metricsFileManager ;
70
72
71
73
public void Start ( )
72
74
{
73
75
Initialize ( ) ;
74
76
75
- _logger . LogInformation ( $ "Starting metrics publisher (AlwaysReady={ IsAlwaysReady } , MetricsPath='{ MetricsFilePath } ').") ;
77
+ _logger . LogInformation ( $ "Starting metrics publisher (AlwaysReady={ IsAlwaysReady } , MetricsPath='{ _metricsFileManager . MetricsFilePath } ').") ;
76
78
77
79
_metricsPublisherTimer = new Timer ( OnFunctionMetricsPublishTimer , null , _initialPublishDelay , _metricPublishInterval ) ;
78
80
_started = true ;
@@ -86,7 +88,6 @@ internal void Initialize()
86
88
_metricPublishInterval = TimeSpan . FromMilliseconds ( _options . MetricsPublishIntervalMS ) ;
87
89
_initialPublishDelay = TimeSpan . FromMilliseconds ( _options . InitialPublishDelayMS ) ;
88
90
_intervalStopwatch = ValueStopwatch . StartNew ( ) ;
89
- MetricsFilePath = _options . MetricsFilePath ;
90
91
91
92
IsAlwaysReady = _environment . GetEnvironmentVariable ( EnvironmentSettingNames . FunctionsAlwaysReadyInstance ) == "1" ;
92
93
}
@@ -136,7 +137,12 @@ internal async Task OnPublishMetrics(DateTime now)
136
137
FunctionExecutionTimeMS = FunctionExecutionCount = 0 ;
137
138
}
138
139
139
- await PublishMetricsAsync ( metrics ) ;
140
+ await _metricsFileManager . PublishMetricsAsync ( metrics ) ;
141
+ }
142
+ catch ( Exception ex ) when ( ! ex . IsFatal ( ) )
143
+ {
144
+ // ensure no background exceptions escape
145
+ _logger . LogError ( ex , $ "Error publishing metrics.") ;
140
146
}
141
147
finally
142
148
{
@@ -149,84 +155,6 @@ private async void OnFunctionMetricsPublishTimer(object state)
149
155
await OnPublishMetrics ( DateTime . UtcNow ) ;
150
156
}
151
157
152
- private async Task PublishMetricsAsync ( Metrics metrics )
153
- {
154
- string fileName = string . Empty ;
155
-
156
- try
157
- {
158
- bool metricsPublishEnabled = ! string . IsNullOrEmpty ( MetricsFilePath ) ;
159
- if ( metricsPublishEnabled && ! PrepareDirectoryForFile ( ) )
160
- {
161
- return ;
162
- }
163
-
164
- string metricsContent = JsonConvert . SerializeObject ( metrics ) ;
165
- _logger . PublishingMetrics ( metricsContent ) ;
166
-
167
- if ( metricsPublishEnabled )
168
- {
169
- fileName = $ "{ Guid . NewGuid ( ) . ToString ( ) . ToLower ( ) } .json";
170
- string filePath = Path . Combine ( MetricsFilePath , fileName ) ;
171
-
172
- using ( var streamWriter = _fileSystem . File . CreateText ( filePath ) )
173
- {
174
- await streamWriter . WriteAsync ( metricsContent ) ;
175
- }
176
- }
177
- }
178
- catch ( Exception ex ) when ( ! ex . IsFatal ( ) )
179
- {
180
- // TODO: consider using a retry strategy here
181
- _logger . LogError ( ex , $ "Error writing metrics file '{ fileName } '.") ;
182
- }
183
- }
184
-
185
- private bool PrepareDirectoryForFile ( )
186
- {
187
- if ( string . IsNullOrEmpty ( MetricsFilePath ) )
188
- {
189
- return false ;
190
- }
191
-
192
- // ensure the directory exists
193
- _fileSystem . Directory . CreateDirectory ( MetricsFilePath ) ;
194
-
195
- var metricsDirectoryInfo = _fileSystem . DirectoryInfo . FromDirectoryName ( MetricsFilePath ) ;
196
- var files = metricsDirectoryInfo . GetFiles ( ) . OrderBy ( p => p . CreationTime ) . ToList ( ) ;
197
-
198
- // ensure we're under the max file count
199
- if ( files . Count < _options . MaxFileCount )
200
- {
201
- return true ;
202
- }
203
-
204
- // we're at or over limit
205
- // delete enough files that we have space to write a new one
206
- int numToDelete = files . Count - _options . MaxFileCount + 1 ;
207
- var filesToDelete = files . Take ( numToDelete ) . ToArray ( ) ;
208
-
209
- _logger . LogDebug ( $ "Deleting { filesToDelete . Length } metrics file(s).") ;
210
-
211
- foreach ( var file in filesToDelete )
212
- {
213
- try
214
- {
215
- file . Delete ( ) ;
216
- }
217
- catch ( Exception ex ) when ( ! ex . IsFatal ( ) )
218
- {
219
- // best effort
220
- _logger . LogError ( ex , $ "Error deleting metrics file '{ file . FullName } '.") ;
221
- }
222
- }
223
-
224
- files = metricsDirectoryInfo . GetFiles ( ) . OrderBy ( p => p . CreationTime ) . ToList ( ) ;
225
-
226
- // return true if we have space for a new file
227
- return files . Count < _options . MaxFileCount ;
228
- }
229
-
230
158
private void OnStandbyOptionsChange ( )
231
159
{
232
160
if ( ! _standbyOptions . CurrentValue . InStandbyMode )
0 commit comments