Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,6 @@ paket-files/

#VS Code
.vscode

#Sonar Lint
.sonarlint
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,68 @@ _logger.LogTrace("This won't be displayed, only critical will be");
_logger.LogCritical("Critical message will be displayed");
```

### Create your own formatting

You can use a custom formatter which will give you the name of the logger, the log level, the event ID, the message itself and a potential exception. The function definition should follow the following pattern:

```csharp
public interface IMessageFormatter
{
string MessageFormatter(string className, LogLevel logLevel, EventId eventId, string state, Exception exception);
}
```

**Important**: this function will be called directly, without instantiating the class it is part of. So make sure either this function is a static, either it's part of the class using the logger. The static option always works. The interface is given for convenience and to give the format.

To setup the formatting, just use the following line. The type of the class containing the function and the exact name of the function are required.

```csharp
LoggerExtensions.MessageFormatter = typeof(MyFormatter).GetType().GetMethod("MessageFormatterStatic");

public class MyFormatter
{
public string MessageFormatterStatic(string className, LogLevel logLevel, EventId eventId, string state, Exception exception)
{
string logstr = string.Empty;
switch (logLevel)
{
case LogLevel.Trace:
logstr = "TRACE: ";
break;
case LogLevel.Debug:
logstr = "I love debug: ";
break;
case LogLevel.Warning:
logstr = "WARNING: ";
break;
case LogLevel.Error:
logstr = "ERROR: ";
break;
case LogLevel.Critical:
logstr = "CRITICAL:";
break;
case LogLevel.None:
case LogLevel.Information:
default:
break;
}

string eventstr = eventId.Id != 0 ? $" Event ID: {eventId}, " : string.Empty;
string msg = $"[{className}] {eventstr}{logstr} {state}";
if (exception != null)
{
msg += $" {exception}";
}

return msg;
}
}
```

You are free to use anything you'd like and format as you like the message.

Note: It is **not** necessary to add a \r\n at the end, this is done by each logger.

## Code of Conduct

This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community.
Expand Down
114 changes: 114 additions & 0 deletions Tests/UnitTestDebugLogging/FormattingTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using nanoFramework.TestFramework;
using System;
using System.Diagnostics;
using nanoFramework.Logging;
using Microsoft.Extensions.Logging;
using nanoFramework.Logging.Debug;

namespace UnitTestDebugLogging
{
[TestClass]
class FormattingTest
{
static DebugLogger _logger;

[Setup]
public void SteupFormattingTest()
{
_logger = new DebugLogger(nameof(FormattingTest));
LoggerExtensions.MessageFormatter = typeof(MyFormatter).GetType().GetMethod("MessageFormatterStatic");
Debug.WriteLine($"{LoggerExtensions.MessageFormatter.Name}");
_logger.MinLogLevel = LogLevel.Trace;
}

[TestMethod]
public void TestInvoke()
{
string msg = (string)LoggerExtensions.MessageFormatter.Invoke(null, new object[] { "test", LogLevel.Trace, new EventId(0), "some text", null });
Debug.WriteLine(msg);
}

[TestMethod]
public void TestFormatting()
{
LogAll();
}

[TestMethod]
public void TestFormattingSimple()
{
LoggerExtensions.MessageFormatter = typeof(MyFormatter).GetType().GetMethod("MessageFormatterSimple");
LogAll();
}

private void LogAll()
{
Debug.WriteLine($"Expexcted level: {_logger.MinLogLevel}");
_logger.LogTrace("{0} {1}", new object[] { "param 1", 42 });
_logger.LogDebug("{0} {1}", new object[] { "param 1", 42 });
_logger.LogInformation("Just some information and nothing else");
_logger.LogWarning("{0} {1}", new object[] { "param 1", 42 });
_logger.LogError(new Exception("Big problem"), "{0} {1}", new object[] { "param 1", 42 });
_logger.LogCritical(42, new Exception("Insane problem"), "{0} {1}", new object[] { "param 1", 42 });
}

[Cleanup]
public void CleanupFormattingTest()
{
LoggerExtensions.MessageFormatter = null;
}
}

public class MyFormatter : IMessageFormatter
{
public string MessageFormatter(string className, LogLevel logLevel, EventId eventId, string state, Exception exception)
=> MessageFormatterStatic(className, logLevel, eventId, state, exception);

public string MessageFormatterStatic(string className, LogLevel logLevel, EventId eventId, string state, Exception exception)
{
string logstr = string.Empty;
switch (logLevel)
{
case LogLevel.Trace:
logstr = "TRACE: ";
break;
case LogLevel.Debug:
logstr = "I love debug: ";
break;
case LogLevel.Warning:
logstr = "WARNING: ";
break;
case LogLevel.Error:
logstr = "ERROR: ";
break;
case LogLevel.Critical:
logstr = "CRITICAL:";
break;
case LogLevel.None:
case LogLevel.Information:
default:
break;
}

string eventstr = eventId.Id != 0 ? $" Event ID: {eventId}, " : string.Empty;
string msg = $"[{className}] {eventstr}{logstr} {state}";
if (exception != null)
{
msg += $" {exception}";
}

return msg;
}

public string MessageFormatterSimple(string className, LogLevel logLevel, EventId eventId, string state, Exception exception)
{
string msg = $"[{className}] {logLevel}-{state}";
if (exception != null)
{
msg += $" {exception}";
}

return msg;
}
}
}
1 change: 1 addition & 0 deletions Tests/UnitTestDebugLogging/UnitTestDebugLogging.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<ItemGroup>
<Compile Include="DebugTest.cs" />
<Compile Include="EventIdTests.cs" />
<Compile Include="FormattingTest.cs" />
<Compile Include="MemoryStreamTests.cs" />
<Compile Include="MyTestComponent.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
25 changes: 21 additions & 4 deletions nanoFramework.Logging.Serial/SerialLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.Extensions.Logging;
using System;
using System.Reflection;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;

Expand All @@ -21,13 +22,20 @@ public class SerialLogger : ILogger
/// Creates a new instance of the <see cref="SerialLogger"/>
/// </summary>
/// <param name="serialDevice">The serial port to use</param>
public SerialLogger(ref SerialDevice serialDevice)
/// <param name="loggerName">The logger name</param>
public SerialLogger(ref SerialDevice serialDevice, string loggerName)
{
SerialDevice = serialDevice;
LoggerName = loggerName;
_outputDataWriter = new DataWriter(serialDevice.OutputStream);
MinLogLevel = LogLevel.Debug;
}

/// <summary>
/// Name of the logger
/// </summary>
public string LoggerName { get; }

/// <summary>
/// Name of the serial device
/// </summary>
Expand All @@ -42,12 +50,21 @@ public SerialLogger(ref SerialDevice serialDevice)
public bool IsEnabled(LogLevel logLevel) => logLevel >= MinLogLevel;

/// <inheritdoc />
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception)
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception, MethodInfo format)
{
if (logLevel >= MinLogLevel)
{
string msg = exception == null ? $"{state}\r\n" : $"{state} {exception}\r\n";
_outputDataWriter.WriteString(msg);
string msgSerial;
if (format == null)
{
msgSerial = exception == null ? $"{state}\r\n" : $"{state} {exception}\r\n";
}
else
{
msgSerial = $"{(string)format.Invoke(null, new object[] { LoggerName, logLevel, eventId, state, exception })}\r\n";
}

_outputDataWriter.WriteString(msgSerial);
_outputDataWriter.Store();
}
}
Expand Down
2 changes: 1 addition & 1 deletion nanoFramework.Logging.Serial/SerialLoggerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public ILogger CreateLogger(string categoryName)
_serial.StopBits = _stopBits;
_serial.Handshake = _handshake;
_serial.DataBits = _dataBits;
return new SerialLogger(ref _serial);
return new SerialLogger(ref _serial, categoryName);
}

/// <inheritdoc />
Expand Down
39 changes: 23 additions & 16 deletions nanoFramework.Logging.Stream/StreamLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Reflection;
using System.Text;

namespace nanoFramework.Logging.Stream
{
/// <summary>
/// A logger that outputs to a <see cref="Stream"/>.
/// </summary>
public class StreamLogger : ILogger, IDisposable
public class StreamLogger : ILogger
{
private System.IO.Stream _stream = null;
private readonly System.IO.Stream _stream = null;

/// <summary>
/// Creates a new instance of the <see cref="ILogger"/>
/// </summary>
/// <param name="stream">Stream to output the log to.</param>
public StreamLogger(System.IO.Stream stream)
/// <param name="loggerName">The logger name</param>
public StreamLogger(System.IO.Stream stream, string loggerName)
{
_stream = stream;
LoggerName = loggerName;
MinLogLevel = LogLevel.Debug;
}

/// <summary>
/// Name of the logger
/// </summary>
public string LoggerName { get; }

/// <summary>
/// Name of the logger
/// </summary>
Expand All @@ -40,25 +48,24 @@ public StreamLogger(System.IO.Stream stream)
public bool IsEnabled(LogLevel logLevel) => logLevel >= MinLogLevel;

/// <inheritdoc />
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception)
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception, MethodInfo format)
{
if (logLevel >= MinLogLevel)
{
string msg = exception == null ? $"{state}\r\n" : $"{state} {exception}\r\n";
byte[] sampleBuffer = Encoding.UTF8.GetBytes(msg);
string msgStream;
if (format == null)
{
msgStream = exception == null ? $"{state}\r\n" : $"{state} {exception}\r\n";
}
else
{
msgStream = $"{(string)format.Invoke(null, new object[] { LoggerName, logLevel, eventId, state, exception })}\r\n";
}

byte[] sampleBuffer = Encoding.UTF8.GetBytes(msgStream);
_stream.Seek(0, SeekOrigin.End);
_stream.Write(sampleBuffer, 0, sampleBuffer.Length);
}
}

/// <inheritdoc/>
public void Dispose()
{
if(_stream != null)
{
_stream.Dispose();
_stream = null;
}
}
}
}
2 changes: 1 addition & 1 deletion nanoFramework.Logging.Stream/StreamLoggerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public ILogger CreateLogger(string categoryName)
throw new IOException();
}

return new StreamLogger(_stream);
return new StreamLogger(_stream, categoryName);
}

/// <inheritdoc />
Expand Down
15 changes: 13 additions & 2 deletions nanoFramework.Logging/DebugLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.Extensions.Logging;
using System;
using System.Reflection;

namespace nanoFramework.Logging.Debug
{
Expand All @@ -16,6 +17,7 @@ public class DebugLogger : ILogger
/// <summary>
/// Creates a new instance of the <see cref="DebugLogger"/>
/// </summary>
/// <param name="loggerName">The logger name</param>
public DebugLogger(string loggerName)
{
LoggerName = loggerName;
Expand All @@ -36,11 +38,20 @@ public DebugLogger(string loggerName)
public bool IsEnabled(LogLevel logLevel) => logLevel >= MinLogLevel;

/// <inheritdoc />
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception)
public void Log(LogLevel logLevel, EventId eventId, string state, Exception exception, MethodInfo format)
{
if (logLevel >= MinLogLevel)
{
string msg = exception == null ? state : $"{state} {exception}";
string msg;
if (format == null)
{
msg = exception == null ? state : $"{state} {exception}";
}
else
{
msg = (string)format.Invoke(null, new object[] { LoggerName, logLevel, eventId, state, exception });
}

System.Diagnostics.Debug.WriteLine(msg);
}
}
Expand Down
Loading