-
Notifications
You must be signed in to change notification settings - Fork 0
/
LogFile.cs
335 lines (277 loc) · 9.22 KB
/
LogFile.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace MigrateData3to4
{
static partial class LogFile
{
const int NumLogFileFields = 29;
const int NumExtraLogFileFields = 92;
const int NumAirLinkLogFileFields = 56;
const int DayfileFields = 55;
static internal void Convert(CustLogs custLogs)
{
// First do the Monthly log files
Console.WriteLine("\nMigrating monthly log files");
Utils.LogMessage("Migrating monthly log files");
DoLogFiles();
// Now the extra Monthly log files
Console.WriteLine("\nMigrating Extra monthly log files");
Utils.LogMessage("Migrating Extra monthly log files");
DoExtraLogFiles();
// Now the AirLink Monthly log files
Console.WriteLine("\nMigrating AirLink monthly log files");
Utils.LogMessage("Migrating AirLink monthly log files");
DoAirLinkLogFiles();
// Now the Custom Monthly log files
Console.WriteLine("\nMigrating Custom monthly log files");
Utils.LogMessage("Migrating Custom monthly log files");
DoCustomMonthlyFiles(custLogs);
// Now the Custom Monthly log files
Console.WriteLine("\nMigrating Custom daily log files");
Utils.LogMessage("Migrating Custom daily log files");
DoCustomDailyFiles(custLogs);
}
private static void DoLogFiles()
{
// Get a list of the files using a regex
var reg = MonthlyLogFilesRegex();
var monFiles = Directory.GetFiles(Program.Src, "*log.txt");
List<string> logFiles = [];
foreach (string file in monFiles)
{
if (reg.IsMatch(Path.GetFileName(file)))
{
logFiles.Add(file);
}
}
Console.WriteLine($"Found {logFiles.Count} monthly log files to process");
Utils.LogMessage($"LogFile: Found {logFiles.Count} monthly log files to process");
DoFiles(logFiles.ToArray(), FileType.Monthly);
}
private static void DoExtraLogFiles()
{
// Get a list of the files
var reg = ExtraMonthlyLogFilesRegex();
var monFiles = Directory.GetFiles(Program.Src, "ExtraLog*.txt").Where(path => reg.IsMatch(path)).ToArray();
Console.WriteLine($"Found {monFiles.Length} monthly Extra log files to process");
Utils.LogMessage($"ExtraLogFile: Found {monFiles.Length} monthly log files to process");
DoFiles(monFiles, FileType.Extra);
}
private static void DoAirLinkLogFiles()
{
// Get a list of the files
var monFiles = Directory.GetFiles(Program.Src, "AirLink*log.txt");
Console.WriteLine($"Found {monFiles.Length} monthly AirLink log files to process");
Utils.LogMessage($"AirLinkLogFile: Found {monFiles.Length} monthly log files to process");
DoFiles(monFiles, FileType.AirLink);
}
private static void DoCustomMonthlyFiles(CustLogs custLogs)
{
if (custLogs.IntvLogs.Count == 0)
{
Console.WriteLine("\nNo Custom interval log files defined in Cumulus.ini");
Utils.LogMessage("No Custom interval log files defined in Cumulus.ini");
}
else
{
// Interval log file names are templates, we need to filnd all the files
foreach (var file in custLogs.IntvLogs)
{
var reg = new Regex(file + @"-20[0-9]{4}\.txt");
var monFiles = Directory.GetFiles(Program.Src, "*.txt").Where(path => reg.IsMatch(path)).ToArray();
Console.WriteLine($" Found {monFiles.Length} custom monthly log files matching \"{file}\" to process");
Utils.LogMessage($"CustomMonthly: Found {monFiles.Length} custom monthly log files matching \"{file}\" to process");
DoFiles(monFiles, FileType.CustomIntv);
}
}
}
private static void DoCustomDailyFiles(CustLogs custLogs)
{
if (custLogs.DailyLogs.Count == 0)
{
Console.WriteLine("\nNo Custom daily log files defined in Cumulus.ini");
Utils.LogMessage("No Custom daily log files defined in Cumulus.ini");
}
else
{
DoFiles(custLogs.DailyLogs.ToArray(), FileType.CustomDaily);
}
}
public static void DoFiles(string[] files, FileType fileType)
{
foreach (var inFile in files)
{
Console.Write(" Processing file " + inFile + "... ");
Utils.LogMessage("Processing file " + inFile);
try
{
if (File.Exists(inFile))
{
var cnt = WriteFileContents(inFile, fileType);
Console.WriteLine("done.");
Utils.LogMessage($"Finished writing to file, lines processed = {cnt}");
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("File not found.");
Utils.LogMessage($"File not found {inFile}");
Console.ResetColor();
}
}
catch (Exception ex)
{
Console.WriteLine($"Error processing log file - {ex.Message}\n");
Utils.LogMessage($"Error processing log {inFile} file - {ex.Message}\n");
}
}
}
/// <summary>
/// All new log files have the same internal format for the first two fields, this copies input to output
/// </summary>
/// <param name="date"></param>
/// <param name="inpFile"></param>
/// <param name="fileType"></param>
/// <returns>Count of the lines processed</returns>
private static int WriteFileContents(string inpFile, FileType fileType)
{
var lineNum = 1;
string outFile;
var fieldCount = fileType switch
{
FileType.Monthly => NumLogFileFields,
FileType.Extra => NumExtraLogFileFields,
FileType.AirLink => NumAirLinkLogFileFields,
FileType.Dayfile => DayfileFields,
_ => -1,
};
try
{
// Custom daily files are just the bare filename
if (fileType == FileType.CustomDaily)
{
inpFile = Program.Src + Path.DirectorySeparatorChar + inpFile;
}
// read the first line to determine format
var lines = File.ReadLines(inpFile).ToArray();
Program.sepField = Utils.GetLogFileSeparator(lines[0], ',');
Utils.LogMessage($"LogFile: File is using the field separator: {Program.sepField}");
if (fileType != FileType.CustomDaily)
{
Program.sepTime = Utils.GetLogFileTimeSeparator(lines[0], ':');
}
Utils.LogMessage($"LogFile: File is using the time separator: {Program.sepTime}");
if (Program.sepTime != ':')
{
for (var i = 0; i < lines.Length; i++)
{
lines[i] = lines[i].Replace(Program.sepTime, ':');
}
}
if (fileType == FileType.Monthly)
{
outFile = Program.Dst + Path.DirectorySeparatorChar + Utils.DdmmyyStrToDate(lines[0].Split(Program.sepField)[0]).ToString("yyyyMM") + "log.txt";
}
else
{
outFile = Program.Dst + Path.DirectorySeparatorChar + inpFile.Split(Path.DirectorySeparatorChar)[^1];
}
Utils.LogMessage($"LogFile: File {inpFile} will be written to {outFile}");
Utils.TryDetectNewLine(inpFile, out string endOfLine);
Utils.LogMessage($"LogFile: File {inpFile} is using the line ending: {(endOfLine == "\n" ? "\\n" : "\\r\\n")}");
using var sw = new StreamWriter(outFile) { NewLine = endOfLine };
for (var l =0; l < lines.Length; l++)
{
var line = lines[l];
if (fileType != FileType.CustomIntv && fileType != FileType.CustomDaily && line[0] < 32)
{
var repLine = RepairLine(line, Program.sepField, fieldCount);
if (repLine == null)
{
Console.WriteLine($" deleted corrupt line {l + 1}");
Utils.LogMessage($"LogFile: File {inpFile} deleted corrupt line {l +1}");
continue;
}
else
{
Console.WriteLine($" repaired corrupt line {l + 1}");
Utils.LogMessage($"LogFile: File {inpFile} repaired corrupt line {l + 1}");
line = repLine;
}
}
var fields = line.Split(Program.sepField);
// Do the date
fields[0] = Utils.DdmmyyStrToStr(fields[0]);
// do the rest of the fields, converting comma decimals to dot
for (var i = 1; i < fields.Length; i++)
{
fields[i] = fields[i].Replace(',', '.');
}
// Write the output
sw.WriteLine(string.Join(',', fields));
lineNum++;
}
sw.Flush();
sw.Close();
}
catch (FileNotFoundException)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"File not found: {inpFile}");
Console.WriteLine($"File not found: {inpFile}\n");
Console.ResetColor();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error at line {lineNum} - {ex.Message}");
Console.WriteLine($"Please fix the file {inpFile} at line {lineNum} and try the migration again\n");
Console.ResetColor();
}
return lineNum - 1;
}
private static string RepairLine(string line, char sep, int recCount)
{
if (recCount < 0)
return null;
try
{
line = new string((from c in line
where char.IsLetterOrDigit(c) || char.IsPunctuation(c)
select c
).ToArray());
// test if it is now valid by spliting into fields and counting them
if (line.Split(sep).Length == recCount)
{
// all good, return the modded line
}
else
{
line = null;
}
}
catch
{
// it failed somewhere, just delete the line
line = null;
}
return line;
}
public enum FileType : ushort
{
Monthly = 0,
Extra = 1,
AirLink = 2,
Dayfile = 3,
CustomIntv = 4,
CustomDaily = 5
}
[GeneratedRegex(@"^\D+[\d]{2}log\.txt")]
private static partial Regex MonthlyLogFilesRegex();
[GeneratedRegex(@"ExtraLog20[\d]{4}\.txt")]
private static partial Regex ExtraMonthlyLogFilesRegex();
}
}