Skip to content

Commit

Permalink
Add Serilog sample to ref servers (#1263)
Browse files Browse the repository at this point in the history
- the Serilog trace event logger replaces the default log output file 
- optional logging to console / debug
  • Loading branch information
mregen committed Feb 2, 2021
1 parent 2392e40 commit 19a9aa4
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
<PackageId>ConsoleReferenceServer</PackageId>
<Company>OPC Foundation</Company>
<Description>.NET Core Reference Server</Description>
<Copyright>Copyright © 2004-2020 OPC Foundation, Inc</Copyright>
<Copyright>Copyright © 2004-2021 OPC Foundation, Inc</Copyright>
</PropertyGroup>

<ItemGroup>
<None Remove="Quickstarts.MonoReferenceServer.Config.xml" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\ReferenceServer\ReferenceNodeManager.cs;..\ReferenceServer\ReferenceServer.cs;..\ReferenceServer\ReferenceServerConfiguration.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
<Compile Include="..\ReferenceServer\ReferenceNodeManager.cs" />
<Compile Include="..\ReferenceServer\ReferenceServerConfiguration.cs" />
<Compile Include="..\ReferenceServer\ReferenceServer.cs" />
<Compile Include="..\ReferenceServer\SerilogTraceLogger.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>

<ItemGroup Condition=" '$(NoHttps)' != 'true' ">
Expand All @@ -27,9 +30,13 @@
<ProjectReference Include="..\..\Libraries\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
<ProjectReference Include="..\..\Libraries\Opc.Ua.Server\Opc.Ua.Server.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Mono.Options" Version="6.6.0.161" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="1.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Applications/ConsoleReferenceServer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
COPY ./publish /publish
WORKDIR /publish

ENTRYPOINT ["dotnet", "NetCoreReferenceServer.dll"]
ENTRYPOINT ["dotnet", "ConsoleReferenceServer.dll"]
161 changes: 92 additions & 69 deletions Applications/ConsoleReferenceServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,51 +31,52 @@
using Opc.Ua;
using Opc.Ua.Configuration;
using Opc.Ua.Server;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace Quickstarts.ReferenceServer
{
public class ApplicationMessageDlg : IApplicationMessageDlg
{
private string message = string.Empty;
private bool ask = false;
private string m_message = string.Empty;
private bool m_ask = false;

public override void Message(string text, bool ask)
{
this.message = text;
this.ask = ask;
m_message = text;
m_ask = ask;
}

public override async Task<bool> ShowAsync()
{
if (ask)
if (m_ask)
{
message += " (y/n, default y): ";
Console.Write(message);
m_message += " (y/n, default y): ";
Console.Write(m_message);
}
else
{
Console.WriteLine(message);
Console.WriteLine(m_message);
}
if (ask)
if (m_ask)
{
try
{
ConsoleKeyInfo result = Console.ReadKey();
Console.WriteLine();
return await Task.FromResult((result.KeyChar == 'y') || (result.KeyChar == 'Y') || (result.KeyChar == '\r'));
return await Task.FromResult((result.KeyChar == 'y') || (result.KeyChar == 'Y') || (result.KeyChar == '\r')).ConfigureAwait(false);
}
catch
{
// intentionally fall through
}
}
return await Task.FromResult(true);
return await Task.FromResult(true).ConfigureAwait(false);
}
}

Expand All @@ -97,10 +98,12 @@ public static int Main(string[] args)
// command line options
bool showHelp = false;
bool autoAccept = false;
bool console = false;

Mono.Options.OptionSet options = new Mono.Options.OptionSet {
{ "h|help", "show this message and exit", h => showHelp = h != null },
{ "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null }
{ "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
{ "c|console", "log trace to console", c => console = c != null }
};

try
Expand Down Expand Up @@ -128,7 +131,7 @@ public static int Main(string[] args)
return (int)ExitCode.ErrorInvalidCommandLine;
}

MyRefServer server = new MyRefServer(autoAccept);
MyRefServer server = new MyRefServer(autoAccept, console);
server.Run();

return (int)MyRefServer.ExitCode;
Expand All @@ -137,40 +140,39 @@ public static int Main(string[] args)

public class MyRefServer
{
ReferenceServer server;
Task status;
DateTime lastEventTime;
static bool autoAccept = false;
static ExitCode exitCode;

public MyRefServer(bool _autoAccept)
private ReferenceServer m_server;
private Task m_status;
private DateTime m_lastEventTime;
private bool m_autoAccept = false;
private bool m_logConsole = false;
private static ExitCode s_exitCode;

public MyRefServer(bool autoAccept, bool logConsole)
{
autoAccept = _autoAccept;
m_autoAccept = autoAccept;
m_logConsole = logConsole;
}

public void Run()
{

try
{
exitCode = ExitCode.ErrorServerNotStarted;
s_exitCode = ExitCode.ErrorServerNotStarted;
ConsoleSampleServer().Wait();
Console.WriteLine("Server started. Press Ctrl-C to exit...");
exitCode = ExitCode.ErrorServerRunning;
s_exitCode = ExitCode.ErrorServerRunning;
}
catch (Exception ex)
{
Utils.Trace("ServiceResultException:" + ex.Message);
Console.WriteLine("Exception: {0}", ex.Message);
exitCode = ExitCode.ErrorServerException;
s_exitCode = ExitCode.ErrorServerException;
return;
}

ManualResetEvent quitEvent = new ManualResetEvent(false);
try
{
Console.CancelKeyPress += (sender, eArgs) =>
{
Console.CancelKeyPress += (sender, eArgs) => {
quitEvent.Set();
eArgs.Cancel = true;
};
Expand All @@ -182,55 +184,75 @@ public void Run()
// wait for timeout or Ctrl-C
quitEvent.WaitOne();

if (server != null)
if (m_server != null)
{
Console.WriteLine("Server stopped. Waiting for exit...");

using (ReferenceServer _server = server)
using (ReferenceServer server = m_server)
{
// Stop status thread
server = null;
status.Wait();
m_server = null;
m_status.Wait();
// Stop server and dispose
_server.Stop();
server.Stop();
}
}

exitCode = ExitCode.Ok;
s_exitCode = ExitCode.Ok;
}

public static ExitCode ExitCode { get => exitCode; }
public static ExitCode ExitCode { get => s_exitCode; }

private static void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
private void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
{
if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
{
e.Accept = autoAccept;
if (autoAccept)
{
Console.WriteLine("Accepted Certificate: {0}", e.Certificate.Subject);
}
else
if (m_autoAccept)
{
Console.WriteLine("Rejected Certificate: {0}", e.Certificate.Subject);
if (!m_logConsole)
{
Console.WriteLine("Accepted Certificate: {0}", e.Certificate.Subject);
}
Utils.Trace(Utils.TraceMasks.Security, "Accepted Certificate: {0}", e.Certificate.Subject);
e.Accept = true;
return;
}
}
if (!m_logConsole)
{
Console.WriteLine("Rejected Certificate: {0} {1}", e.Error, e.Certificate.Subject);
}
Utils.Trace(Utils.TraceMasks.Security, "Rejected Certificate: {0} {1}", e.Error, e.Certificate.Subject);
}

private async Task ConsoleSampleServer()
{
ApplicationInstance.MessageDlg = new ApplicationMessageDlg();
ApplicationInstance application = new ApplicationInstance();

application.ApplicationName = "Quickstart Reference Server";
application.ApplicationType = ApplicationType.Server;
application.ConfigSectionName = Utils.IsRunningOnMono() ? "Quickstarts.MonoReferenceServer" : "Quickstarts.ReferenceServer";
ApplicationInstance application = new ApplicationInstance {
ApplicationName = "Quickstart Reference Server",
ApplicationType = ApplicationType.Server,
ConfigSectionName = Utils.IsRunningOnMono() ? "Quickstarts.MonoReferenceServer" : "Quickstarts.ReferenceServer"
};

// load the application configuration.
ApplicationConfiguration config = await application.LoadApplicationConfiguration(false);
ApplicationConfiguration config = await application.LoadApplicationConfiguration(false).ConfigureAwait(false);

var loggerConfiguration = new Serilog.LoggerConfiguration();
if (m_logConsole)
{
loggerConfiguration.WriteTo.Console(restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Warning);
}
#if DEBUG
else
{
loggerConfiguration.WriteTo.Debug(restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Warning);
}
#endif
SerilogTraceLogger.Create(loggerConfiguration, config);

// check the application certificate.
bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, CertificateFactory.DefaultKeySize, CertificateFactory.DefaultLifeTime);
bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(
false, CertificateFactory.DefaultKeySize, CertificateFactory.DefaultLifeTime).ConfigureAwait(false);
if (!haveAppCertificate)
{
throw new Exception("Application instance certificate invalid!");
Expand All @@ -242,8 +264,8 @@ private async Task ConsoleSampleServer()
}

// start the server.
server = new ReferenceServer();
await application.Start(server);
m_server = new ReferenceServer();
await application.Start(m_server).ConfigureAwait(false);

// print endpoint info
var endpoints = application.Server.GetEndpoints().Select(e => e.EndpointUrl).Distinct();
Expand All @@ -253,56 +275,57 @@ private async Task ConsoleSampleServer()
}

// start the status thread
status = Task.Run(new Action(StatusThread));
m_status = Task.Run(new Action(StatusThread));

// print notification on session events
server.CurrentInstance.SessionManager.SessionActivated += EventStatus;
server.CurrentInstance.SessionManager.SessionClosing += EventStatus;
server.CurrentInstance.SessionManager.SessionCreated += EventStatus;
m_server.CurrentInstance.SessionManager.SessionActivated += EventStatus;
m_server.CurrentInstance.SessionManager.SessionClosing += EventStatus;
m_server.CurrentInstance.SessionManager.SessionCreated += EventStatus;
}

private void EventStatus(Session session, SessionEventReason reason)
{
lastEventTime = DateTime.UtcNow;
m_lastEventTime = DateTime.UtcNow;
PrintSessionStatus(session, reason.ToString());
}

void PrintSessionStatus(Session session, string reason, bool lastContact = false)
private void PrintSessionStatus(Session session, string reason, bool lastContact = false)
{
lock (session.DiagnosticsLock)
{
string item = String.Format("{0,9}:{1,20}:", reason, session.SessionDiagnostics.SessionName);
StringBuilder item = new StringBuilder();
item.Append(string.Format("{0,9}:{1,20}:", reason, session.SessionDiagnostics.SessionName));
if (lastContact)
{
item += String.Format("Last Event:{0:HH:mm:ss}", session.SessionDiagnostics.ClientLastContactTime.ToLocalTime());
item.Append(string.Format("Last Event:{0:HH:mm:ss}", session.SessionDiagnostics.ClientLastContactTime.ToLocalTime()));
}
else
{
if (session.Identity != null)
{
item += String.Format(":{0,20}", session.Identity.DisplayName);
item.Append(string.Format(":{0,20}", session.Identity.DisplayName));
}
item += String.Format(":{0}", session.Id);
item.Append(string.Format(":{0}", session.Id));
}
Console.WriteLine(item);
Console.WriteLine(item.ToString());
}
}

private async void StatusThread()
{
while (server != null)
while (m_server != null)
{
if (DateTime.UtcNow - lastEventTime > TimeSpan.FromMilliseconds(6000))
if (DateTime.UtcNow - m_lastEventTime > TimeSpan.FromMilliseconds(6000))
{
IList<Session> sessions = server.CurrentInstance.SessionManager.GetSessions();
IList<Session> sessions = m_server.CurrentInstance.SessionManager.GetSessions();
for (int ii = 0; ii < sessions.Count; ii++)
{
Session session = sessions[ii];
PrintSessionStatus(session, "-Status-", true);
}
lastEventTime = DateTime.UtcNow;
m_lastEventTime = DateTime.UtcNow;
}
await Task.Delay(1000);
await Task.Delay(1000).ConfigureAwait(false);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions Applications/ConsoleReferenceServer/dockerbuild.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
REM build a docker container of the console reference server
dotnet build NetCoreReferenceServer.csproj
dotnet publish NetCoreReferenceServer.csproj -o ./publish
docker build -t netcorerefserver .
dotnet build ConsoleReferenceServer.csproj
dotnet publish ConsoleReferenceServer.csproj -o ./publish
docker build -t consolerefserver .
6 changes: 3 additions & 3 deletions Applications/ConsoleReferenceServer/dockerbuild.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
echo build a docker container of the .NET Core reference server
dotnet build NetCoreReferenceServer.csproj
dotnet publish NetCoreReferenceServer.csproj -o ./publish
sudo docker build -t netcorerefserver .
dotnet build ConsoleReferenceServer.csproj
dotnet publish ConsoleReferenceServer.csproj -o ./publish
sudo docker build -t consolerefserver .
2 changes: 1 addition & 1 deletion Applications/ConsoleReferenceServer/dockerrun.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
echo Run a docker container of the console reference server
echo The certificate store of the ref server is mapped to './OPC Foundation'
docker run -it -p 62541:62541 -h refserver -v "%CD%/OPC Foundation:/root/.local/share/OPC Foundation" netcorerefserver:latest
docker run -it -p 62541:62541 -h refserver -v "%CD%/OPC Foundation:/root/.local/share/OPC Foundation" consolerefserver:latest
2 changes: 1 addition & 1 deletion Applications/ConsoleReferenceServer/dockerrun.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
echo Run a docker container of the console reference server
echo The certificate store of the ref server is mapped to './OPC Foundation'
sudo docker run -it -p 62541:62541 -h refserver -v "$(pwd)/OPC Foundation:/root/.local/share/OPC Foundation" netcorerefserver:latest
sudo docker run -it -p 62541:62541 -h refserver -v "$(pwd)/OPC Foundation:/root/.local/share/OPC Foundation" consolerefserver:latest

0 comments on commit 19a9aa4

Please sign in to comment.