Skip to content

Commit e5623ab

Browse files
committed
Finish up the runtime
1 parent 680ca40 commit e5623ab

39 files changed

+1525
-155
lines changed

WPILib.sln

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "newcommands", "src\newcomma
4949
EndProject
5050
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "epilogue", "src\epilogue\epilogue.csproj", "{B8A9AFC6-01F1-44AC-95D4-0683EF31E117}"
5151
EndProject
52+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "epilogue.test", "test\epilogue.test\epilogue.test.csproj", "{A658C098-9968-4F4A-9230-C91B40FF7541}"
53+
EndProject
5254
Global
5355
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5456
Debug|Any CPU = Debug|Any CPU
@@ -134,6 +136,10 @@ Global
134136
{B8A9AFC6-01F1-44AC-95D4-0683EF31E117}.Debug|Any CPU.Build.0 = Debug|Any CPU
135137
{B8A9AFC6-01F1-44AC-95D4-0683EF31E117}.Release|Any CPU.ActiveCfg = Release|Any CPU
136138
{B8A9AFC6-01F1-44AC-95D4-0683EF31E117}.Release|Any CPU.Build.0 = Release|Any CPU
139+
{A658C098-9968-4F4A-9230-C91B40FF7541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
140+
{A658C098-9968-4F4A-9230-C91B40FF7541}.Debug|Any CPU.Build.0 = Debug|Any CPU
141+
{A658C098-9968-4F4A-9230-C91B40FF7541}.Release|Any CPU.ActiveCfg = Release|Any CPU
142+
{A658C098-9968-4F4A-9230-C91B40FF7541}.Release|Any CPU.Build.0 = Release|Any CPU
137143
EndGlobalSection
138144
GlobalSection(NestedProjects) = preSolution
139145
{8F38C25E-641E-47FC-AC0A-0717F2159E8F} = {DB664556-4BF0-4874-8CB6-DC24E60A67AF}
@@ -154,5 +160,6 @@ Global
154160
{A364B855-95A2-435D-A627-A25F1215AB4E} = {1CA9AB3B-4828-4F07-8C0E-88EF7C5A9ACD}
155161
{B09918CC-E71F-4E49-AA20-81559D3583B2} = {DB664556-4BF0-4874-8CB6-DC24E60A67AF}
156162
{B8A9AFC6-01F1-44AC-95D4-0683EF31E117} = {DB664556-4BF0-4874-8CB6-DC24E60A67AF}
163+
{A658C098-9968-4F4A-9230-C91B40FF7541} = {AD95ECD8-E708-4FB4-9B7E-A8A8EF3FCB3E}
157164
EndGlobalSection
158165
EndGlobal
+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace Epilogue;
22

33
[AttributeUsage(AttributeTargets.Class)]
4-
public sealed class CustomLoggerForAttribute : Attribute {
4+
public sealed class CustomLoggerForAttribute : Attribute
5+
{
56
Type[] Types { get; init; } = [];
6-
}
7+
}

src/epilogue/EpilogueConfiguration.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
using Epilogue.Logging;
2+
using Epilogue.Logging.Errors;
13
using NetworkTables;
24

35
namespace Epilogue;
46

5-
public class EpilogueConfiguration {
6-
public DataLogger DataLogger { get; set; } = new NTDataLogger(NetworkTableInstance.Default);
7+
public class EpilogueConfiguration
8+
{
9+
public IDataLogger DataLogger { get; set; } = new NTDataLogger(NetworkTableInstance.Default);
710
public LogImportance MinimumImportance { get; set; } = LogImportance.Debug;
8-
public ErrorHandler ErrorHandler { get; set; } = new();
11+
public IErrorHandler ErrorHandler { get; set; } = new ErrorPrinter();
912
public string Root { get; set; } = "Robot";
10-
}
13+
}

src/epilogue/LogImportance.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
namespace Epilogue;
22

3-
public enum LogImportance {
3+
public enum LogImportance
4+
{
45
Debug,
56
Info,
67
Critical,
7-
}
8+
}

src/epilogue/LogStrategy.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace Epilogue;
22

3-
public enum LogStrategy {
3+
public enum LogStrategy
4+
{
45
OptIn,
56
OptOut,
6-
}
7+
}

src/epilogue/LoggedAttribute.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ public sealed class LoggedAttribute : Attribute
66
public string Name { get; init; } = "";
77
public LogStrategy Strategy { get; init; } = LogStrategy.OptOut;
88
public LogImportance Importance { get; init; } = LogImportance.Debug;
9-
}
9+
}
+35-15
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,71 @@
1+
using System.Runtime.InteropServices;
2+
using Epilogue.Logging.Errors;
13
using WPIUtil.Sendable;
24

35
namespace Epilogue.Logging;
46

5-
public abstract class ClassSpecificLogger {
7+
public abstract class ClassSpecificLogger
8+
{
69
private readonly Dictionary<ISendable, ISendableBuilder> m_sendables = [];
710

8-
protected ClassSpecificLogger(Type loggedType) {
11+
protected ClassSpecificLogger(Type loggedType)
12+
{
913
LoggedType = loggedType;
1014
}
1115

1216
public bool Disabled { get; private set; }
1317

14-
public void Disable() {
18+
public void Disable()
19+
{
1520
Disabled = true;
1621
}
1722

18-
public void Reenable() {
23+
public void Reenable()
24+
{
1925
Disabled = false;
2026
}
2127

2228
public Type LoggedType { get; }
2329

24-
protected virtual void LogSendable(DataLogger dataLogger, ISendable? sendable) {
25-
if (sendable == null) {
30+
protected virtual void LogSendable(IDataLogger dataLogger, ISendable? sendable)
31+
{
32+
if (sendable is null)
33+
{
2634
return;
2735
}
2836

29-
var builder = m_sendables.
30-
}
37+
ref ISendableBuilder? builder = ref CollectionsMarshal.GetValueRefOrAddDefault(m_sendables, sendable, out var _);
38+
if (builder is null)
39+
{
40+
builder = new LogBackedSenabledBuilder(dataLogger);
41+
sendable.InitSendable(builder);
42+
}
43+
builder.Update();
44+
}
3145
}
3246

33-
public abstract class ClassSpecificLogger<T> : ClassSpecificLogger {
47+
public abstract class ClassSpecificLogger<T> : ClassSpecificLogger
48+
{
3449
protected ClassSpecificLogger() : base(typeof(T))
3550
{
3651
}
3752

38-
protected abstract void Update(DataLogger dataLogger, T obj);
53+
protected abstract void Update(IDataLogger dataLogger, T obj);
3954

40-
public void TryUpdate(DataLogger dataLogger, T obj, ErrorHandler errorHandler) {
41-
if (Disabled) {
55+
public void TryUpdate(IDataLogger dataLogger, T obj, IErrorHandler errorHandler)
56+
{
57+
if (Disabled)
58+
{
4259
return;
4360
}
4461

45-
try {
62+
try
63+
{
4664
Update(dataLogger, obj);
47-
} catch (Exception e) {
48-
errorHandler(e, this);
65+
}
66+
catch (Exception e)
67+
{
68+
errorHandler.Handle(e, this);
4969
}
5070
}
5171
}

src/epilogue/Logging/DataLogger.cs

-9
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
namespace Epilogue.Logging.Errors;
3+
4+
public class CrashOnError : IErrorHandler
5+
{
6+
public void Handle(Exception exception, ClassSpecificLogger logger)
7+
{
8+
#pragma warning disable CA2201 // Do not raise reserved exception types
9+
throw new Exception($"[EPILOGUE] An error occured while logging an instance of {logger.LoggedType.Name}", exception);
10+
#pragma warning restore CA2201 // Do not raise reserved exception types
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
namespace Epilogue.Logging.Errors;
3+
4+
public class ErrorPrinter : IErrorHandler
5+
{
6+
public void Handle(Exception exception, ClassSpecificLogger logger)
7+
{
8+
Console.Error.WriteLine($"[EPILOGUE] An error occured while logging an instance of {logger.LoggedType.Name}: {exception.Message}");
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
namespace Epilogue.Logging.Errors;
22

3-
public interface IErrorHandler {
3+
public interface IErrorHandler
4+
{
45
void Handle(Exception exception, ClassSpecificLogger logger);
56

67
public static IErrorHandler CrashOnError() => new CrashOnError();
78

8-
public static IErrorHandler PrintErrorMessages() => new ErrorPrint();
9+
public static IErrorHandler PrintErrorMessages() => new ErrorPrinter();
910

1011
public static LoggerDisabler Disabling(int maximumPermissableErrors) => LoggerDisabler.ForLimit(maximumPermissableErrors);
1112
}
+25-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,39 @@
11

2+
using System.Runtime.InteropServices;
3+
24
namespace Epilogue.Logging.Errors;
35

4-
public class LoggerDisabler : IErrorHandler {
6+
public class LoggerDisabler : IErrorHandler
7+
{
58
private readonly int m_threshold;
69
private readonly Dictionary<ClassSpecificLogger, int> m_errorCounts = [];
710

8-
public LoggerDisabler(int threshold) {
11+
public LoggerDisabler(int threshold)
12+
{
913
m_threshold = threshold;
1014
}
1115

12-
public static LoggerDisabler ForLimit(int threshold) => new LoggerDisabler(threshold);
16+
public static LoggerDisabler ForLimit(int threshold) => new(threshold);
1317

1418
public void Handle(Exception exception, ClassSpecificLogger logger)
1519
{
16-
throw new NotImplementedException();
20+
int errorCount = ++CollectionsMarshal.GetValueRefOrAddDefault(m_errorCounts, logger, out var _);
21+
22+
if (errorCount > m_threshold)
23+
{
24+
logger.Disable();
25+
Console.Error.WriteLine($"[EPILOGUE] Too many errors detected in {logger.GetType().Name} (maximum allowed: {m_threshold}). The most recent error follows:");
26+
Console.Error.WriteLine(exception.Message);
27+
Console.Error.WriteLine(exception.StackTrace);
28+
}
29+
}
30+
31+
public void Reset()
32+
{
33+
foreach (var logger in m_errorCounts)
34+
{
35+
logger.Key.Reenable();
36+
}
37+
m_errorCounts.Clear();
1738
}
1839
}

src/epilogue/Logging/FileLogger.cs

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using System.Runtime.InteropServices;
2+
using WPIUtil.Logging;
3+
using WPIUtil.Serialization.Struct;
4+
using static WPIUtil.WpiGuard;
5+
6+
namespace Epilogue.Logging;
7+
8+
public class FileLogger : IDataLogger
9+
{
10+
private readonly DataLog m_dataLog;
11+
private readonly Dictionary<string, DataLogEntry> m_entries = [];
12+
private readonly Dictionary<string, SubLogger> m_subLoggers = [];
13+
14+
public FileLogger(DataLog dataLog)
15+
{
16+
m_dataLog = RequireNotNull(dataLog);
17+
}
18+
19+
public IDataLogger Lazy => new LazyLogger(this);
20+
public IDataLogger GetSubLogger(string path) => IDataLogger.GetDefaultSubLogger(this, path, m_subLoggers);
21+
22+
private E GetEntry<E>(string identifier, Func<DataLog, string, E> ctor) where E : DataLogEntry
23+
{
24+
ref var entry = ref CollectionsMarshal.GetValueRefOrAddDefault(m_entries, identifier, out var _);
25+
entry ??= ctor(m_dataLog, identifier);
26+
return (E)entry;
27+
}
28+
29+
public void Log(string identifier, bool value)
30+
{
31+
GetEntry(identifier, static (a, b) => new BooleanLogEntry(a, b)).Append(value);
32+
}
33+
34+
public void Log(string identifier, int value)
35+
{
36+
GetEntry(identifier, static (a, b) => new IntegerLogEntry(a, b)).Append(value);
37+
}
38+
39+
public void Log(string identifier, long value)
40+
{
41+
GetEntry(identifier, static (a, b) => new IntegerLogEntry(a, b)).Append(value);
42+
}
43+
44+
public void Log(string identifier, float value)
45+
{
46+
GetEntry(identifier, static (a, b) => new FloatLogEntry(a, b)).Append(value);
47+
}
48+
49+
public void Log(string identifier, double value)
50+
{
51+
GetEntry(identifier, static (a, b) => new DoubleLogEntry(a, b)).Append(value);
52+
}
53+
54+
public void Log(string identifier, ReadOnlySpan<byte> value)
55+
{
56+
GetEntry(identifier, static (a, b) => new RawLogEntry(a, b)).Append(value);
57+
}
58+
59+
public void Log(string identifier, ReadOnlySpan<bool> value)
60+
{
61+
GetEntry(identifier, static (a, b) => new BooleanArrayLogEntry(a, b)).Append(value);
62+
}
63+
64+
public void Log(string identifier, ReadOnlySpan<int> value)
65+
{
66+
long[] widended = new long[value.Length];
67+
for (int i = 0; i < value.Length; i++)
68+
{
69+
widended[i] = value[i];
70+
}
71+
GetEntry(identifier, static (a, b) => new IntegerArrayLogEntry(a, b)).Append(widended);
72+
}
73+
74+
public void Log(string identifier, ReadOnlySpan<long> value)
75+
{
76+
GetEntry(identifier, static (a, b) => new IntegerArrayLogEntry(a, b)).Append(value);
77+
}
78+
79+
public void Log(string identifier, ReadOnlySpan<float> value)
80+
{
81+
GetEntry(identifier, static (a, b) => new FloatArrayLogEntry(a, b)).Append(value);
82+
}
83+
84+
public void Log(string identifier, ReadOnlySpan<double> value)
85+
{
86+
GetEntry(identifier, static (a, b) => new DoubleArrayLogEntry(a, b)).Append(value);
87+
}
88+
89+
public void Log(string identifier, string value)
90+
{
91+
GetEntry(identifier, static (a, b) => new StringLogEntry(a, b)).Append(value);
92+
}
93+
94+
public void Log(string identifier, ReadOnlySpan<char> value)
95+
{
96+
GetEntry(identifier, static (a, b) => new StringLogEntry(a, b)).Append(value);
97+
}
98+
99+
public void Log(string identifier, ReadOnlySpan<string> value)
100+
{
101+
GetEntry(identifier, static (a, b) => new StringArrayLogEntry(a, b)).Append(value);
102+
}
103+
104+
public void Log<T>(string identifier, in T value) where T : IStructSerializable<T>
105+
{
106+
GetEntry(identifier, static (a, b) => new StructLogEntry<T>(a, b)).Append(value);
107+
}
108+
109+
public void Log<T>(string identifier, T[] value) where T : IStructSerializable<T>
110+
{
111+
GetEntry(identifier, static (a, b) => new StructArrayLogEntry<T>(a, b)).Append(value);
112+
}
113+
114+
public void Log<T>(string identifier, Span<T> value) where T : IStructSerializable<T>
115+
{
116+
GetEntry(identifier, static (a, b) => new StructArrayLogEntry<T>(a, b)).Append(value);
117+
}
118+
119+
public void Log<T>(string identifier, ReadOnlySpan<T> value) where T : IStructSerializable<T>
120+
{
121+
GetEntry(identifier, static (a, b) => new StructArrayLogEntry<T>(a, b)).Append(value);
122+
}
123+
124+
public void Log<T>(string identifier, T value) where T : Enum
125+
{
126+
GetEntry(identifier, static (a, b) => new StringLogEntry(a, b)).Append(value.ToString());
127+
}
128+
}

0 commit comments

Comments
 (0)