Windows IoT Core: Logging to Syslog server
Syslog servers are most popular in Linux world. These servers accept logs from different clients and are not opened to external network. There are also Syslog servers available for Windows. This blog post shows how to write messages to Syslog server from WIndows 10 IoT Core background application.
Syslog server
Syslog server is logging server. Usually it is separate box or virtual machine that is configured to accept log messages and not accept any users from external network. If some system or device gets hacked then usually Syslog server is not accessible and logs are there to analyze what happened.
Example of network with Syslog server.
Copyright belongs to Network Management Software
For more information about Syslog server follow these links:
- Syslog page at Wikipedia
- Understanding Syslog: Servers, Messages & Security (Network Management Software)
- Visual Syslog Server – free Syslog server for Windows
ILogger interface
In my TemperatureStation IoT solution I use ILogger interface to support multiple logger implementations.
internal interface ILogger
{
void Debug(string message);
void Info(string message);
void Warn(string message);
void Error(string message);
void Critical(string message);
}
Now let’s get to logger implementation.
Adding support for syslog server
To write logger for Syslog server we need enum with log levels. These doesn’t match completely with ones used in .NET based logging solutions.
public enum SyslogLogLevel
{
Emergency,
Alert,
Critical,
Error,
Warn,
Notice,
Info,
Debug
}
And here is the logger class for Syslog. It’s simple and primitive but it works. The most important method in this class is Send() method. All other methods are just shortcuts for it that come in with ILogger interface.
internal class SyslogLogger : ILogger
{
private const string SyslogClientName = "RPI-001";
private const string SyslogHost = "192.168.210.2";
private const int SyslogPort = 514;
private const int SyslogFacility = 16;
public void Critical(string message)
{
Send(SyslogLogLevel.Critical, message);
}
public void Debug(string message)
{
Send(SyslogLogLevel.Debug, message);
}
public void Error(string message)
{
Send(SyslogLogLevel.Error, message);
}
public void Info(string message)
{
Send(SyslogLogLevel.Info, message);
}
public void Warn(string message)
{
Send(SyslogLogLevel.Warn, message);
}
internal static void Send(SyslogLogLevel logLevel, string message)
{
if (string.IsNullOrWhiteSpace(SyslogHost) || SyslogPort <= 0)
{
return;
}
var hostName = Dns.GetHostName();
var level = SyslogFacility * 8 + (int)logLevel;
var logMessage = string.Format("<{0}>{1} {2}", level, hostName, message);
var bytes = Encoding.UTF8.GetBytes(logMessage);
using (var client = new UdpClient())
{
client.SendAsync(bytes, bytes.Length, SyslogHost, SyslogPort)
.Wait();
}
}
}
Here is the fragment of code that shows how loggers based on ILogger interface are used in my TemperatureStation solution.
_logger.Info("Timer callback: reading and reporting sensors");
try
{
var readings = _sensorsClient.ReadSensors();
await _reportingClient.ReportReadings(readings);
_logger.Info(readings.ToString());
}
catch (Exception ex)
{
_logger.Critical(ex.ToString());
}
_logger.Info("Timer callback: reading and reporting is done");
And here is how Visual Syslog Server monitor is displaying messages sent from my RaspberryPI.
NB! You can use the same code also with Linux based Syslog servers as they share the same protocol.
Wrapping up
Connecting good things from two worlds may work out as perfect solution. Here we took Syslog server that is popular in Linux world and used it as logging solution for IoT service running on Windows IoT Core and RaspberryPI. We wrote some lines of code to make it work and we were able to send log messages to Syslog server.
Maybe I’m wrong but isn’t there a potential life time problem with this sending code?
using (var client = new UdpClient())
{
client.SendAsync(bytes, bytes.Length, SyslogHost, SyslogPort)
.Wait();
}
If SendAsync is slow (e.g. under high system load) Dispose on the UdpClient could be called before the sending is complete (or rather started at all) and thus we might lose our beautiful log message silently or worse get an uncaught exception in a threadpool thread that might tear down the app if we forget to hook up on such uncaught exceptions. Or is this not an issue? Haven’t checked this deeply but I’m worried.
Let me take this back, I missed the Wait() at the end :)! But if you’re going to Wait() anyway I’d suggest usng Send() directly instead of SendAsync() to not spend as much resources.
On UWP we don’t have Send(), we have only SendAsync() and if we are not interested in asynchrounous call then we can wait just like I did here.
Thanks, I see, please let me take back everything :).
Why? You are on a right track here. Actually for UWP and ASP.NET Core I should be able to use shared logger interface and on both I can go with async code. ASP.NET Core has full support for it.