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
6 changes: 3 additions & 3 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"AXSharp.ixc": {
"version": "0.14.0-alpha.106",
"version": "0.14.0-alpha.108",
"commands": [
"ixc"
]
Expand All @@ -15,13 +15,13 @@
]
},
"AXSharp.ixd": {
"version": "0.14.0-alpha.107",
"version": "0.14.0-alpha.108",
"commands": [
"ixd"
]
},
"AXSharp.ixr": {
"version": "0.14.0-alpha.106",
"version": "0.14.0-alpha.108",
"commands": [
"ixr"
]
Expand Down
48 changes: 48 additions & 0 deletions docfx/articles/logging/AXOLOGGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,41 @@ The `Foo` method retrieves the context's logger using `THIS.GetContext().GetLogg
## Summary
Through this example, we've shown how to declare and utilize the `AxoLogger` for logging messages with different levels of severity. We've also illustrated how nested objects can retrieve and use the logger of their parent context to log messages, showcasing a flexible and potent approach to handle logging in applications with complex, nested structures.



# Initialization of Logger in .NET

In this section, we'll be discussing how to initialize the logger in a .NET application, specifically using the Serilog library for logging. We'll also demonstrate how to link the logger to our `AxoLogger` instances from our previous examples: `LoggerOne` and `LoggerTwo`.

## Initializing Object Identities

Before you start logging with `AxoLogger`, you need to ensure the object identities are initialized. This is important because it allows the `AxoLogger` to correctly identify the source of log messages, which aids in debugging and log analysis.

To initialize the object identities in a .NET part of your application, use the following method:

```csharp
await Entry.Plc.Connector.IdentityProvider.ConstructIdentitiesAsync();
```

This method call is usually performed during the application initialization process, right after the `AxoApplication` and loggers are configured. It constructs all the identities required by the application, preparing the `AxoLogger` for logging.

Here's how it could fit into the .NET application initialization process:

```csharp

// Initialize the object identities.
Entry.Plc.Connector.SubscriptionMode = ReadSubscriptionMode.Polling;
Entry.Plc.Connector.BuildAndStart().ReadWriteCycleDelay = 250;
await Entry.Plc.Connector.IdentityProvider.ConstructIdentitiesAsync();
```

This sets up the `AxoApplication`, configures a logger with Serilog, initializes the object identities, and then connects `AxoLogger` instances to the application.

Remember to always await the `ConstructIdentitiesAsync` method, as it is an asynchronous operation and your application should not proceed until it has been completed. This ensures all object identities are fully initialized before your `AxoLogger` instances start logging.

> [!IMPORTANT]
> Failure to initialize object identities before starting the logging process can result in incorrect or incomplete log entries, which can hinder the debugging and analysis of your application. Always ensure that object identities are correctly initialized before you start logging.

## Creating the AxoApplication
Before initializing the logger, we first create an instance of `AxoApplication` using the `CreateBuilder` method. This sets up the application builder required for the logger configuration.

Expand Down Expand Up @@ -105,6 +136,23 @@ This example showcases how to initialize a logger in a .NET application using th
> In the context of logging level configuration, it's important to note that the minimum logging level of the .NET logger (set up in C#) and the `AxoLogger` (set up in the controller's software) are independent settings. You can configure them individually to fine-tune the verbosity of your logs both at the controller level and in your .NET application.


## AxoLogger and AxoMessenger

AxoMessenger uses Context AxoLogger to log the rising and falling of an alarm. There is no particular need for the configuration fo this behaviour.

Here are the mappings between eAxoMessageCategory and eLogLevel as per the code:

- Trace messages are logged as Verbose.
- Debug messages are logged as Debug.
- Info, TimedOut, and Notification messages are logged as - Information.
- Warning messages are logged as Warning.
- Error and ProgrammingError messages are logged as Error.
- Critical, Fatal, and Catastrophic messages are logged as Fatal.





# Limitations

## Log Entry Limit
Expand Down
2 changes: 2 additions & 0 deletions docfx/articles/messaging/AXOMESSENGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ Contrariwise, the default behaviour of the unacknowledgeable messenger should be
On the UI side use the `RenderableContentControl` and set its Context according the placement of the instance of the `AxoMessenger`.
[!code-csharp[](../../../src/integrations/src/AXOpen.Integrations.Blazor/Pages/DocuExamples/AxoMessagingStaticDocu.razor?name=RenderedView)]


See also [AxoLogger](../logging/AXOLOGGER.md#axologger-and-axomessenger)
2 changes: 1 addition & 1 deletion src/AXOpen.sln
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "axopen_integrations_blazor"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AXOpen.Security.Blazor", "security\src\AXOpen.Security.Blazor\AXOpen.Security.Blazor.csproj", "{7DEF0B7B-0F6C-4829-A1A9-2C0C2720BF3C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AXOpen.Security", "security\src\AXOpen.Security\AXOpen.Security.csproj", "{52B6EFDD-8FF9-4FA7-9624-2E7D8EEDD5C1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AXOpen.Security", "security\src\AXOpen.Security\AXOpen.Security.csproj", "{52B6EFDD-8FF9-4FA7-9624-2E7D8EEDD5C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AXSharp.Abstractions" Version="0.14.0-alpha.106" />
<PackageReference Include="AXSharp.Connector" Version="0.14.0-alpha.106" />
<PackageReference Include="AXSharp.Abstractions" Version="0.14.0-alpha.108" />
<PackageReference Include="AXSharp.Connector" Version="0.14.0-alpha.108" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageReference Include="Microsoft.AspNetCore.Components" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="5.0.7" />
<PackageReference Include="AXSharp.Connector" Version="0.14.0-alpha.106" />
<PackageReference Include="AXSharp.Connector" Version="0.14.0-alpha.108" />
</ItemGroup>

<ItemGroup>
Expand Down
17 changes: 8 additions & 9 deletions src/base/src/AXOpen.Logging/SerilogLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void Debug(string message, IIdentity identity)
public void Debug(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Debug<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable },
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
Expand All @@ -50,7 +50,7 @@ public void Verbose(string message, IIdentity identity)
public void Verbose(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Verbose<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable },
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
Expand All @@ -64,10 +64,9 @@ public void Information(string message, IIdentity identity)
public void Information(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Information<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable},
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details);
}

public void Warning(string message, IIdentity identity)
Expand All @@ -78,7 +77,7 @@ public void Warning(string message, IIdentity identity)
public void Warning(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Warning<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable },
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
Expand All @@ -92,7 +91,7 @@ public void Error(string message, IIdentity identity)
public void Error(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Error<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable },
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
Expand All @@ -106,7 +105,7 @@ public void Fatal(string message, IIdentity identity)
public void Fatal(string message, ITwinElement sender, IIdentity identity, object details)
{
Log.Fatal<object, object, object>($"{message} {{sender}} {{identity}} {{details}}",
new { Symbol = sender.Symbol, Label = sender.HumanReadable },
new { Symbol = sender?.Symbol, Label = sender?.HumanReadable },
new { UserName = identity.Name, Type = identity.AuthenticationType },
details
);
Expand Down
15 changes: 0 additions & 15 deletions src/core/ctrl/.vscode/launch.json

This file was deleted.

1 change: 1 addition & 0 deletions src/core/ctrl/apax.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ version: '0.1.4-alpha.79'
type: lib
targets:
- axunit-llvm
- llvm
files:
- src
devDependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ NAMESPACE AXOpen.Core
THIS.OnBeforeSequenceStart();
CurrentOrder := ULINT#1;
_coordinatorState := AxoCoordinatorStates#Running;
THIS.GetContext().GetLogger().Log('Sequence in config state :', AXOpen.Logging.eLogLevel#Verbose, THIS);
END_CASE;
Open := TRUE;
END_IF;
Expand All @@ -61,7 +62,7 @@ NAMESPACE AXOpen.Core
_step := step;

THIS.DetermineOrder(step);

// Stepping inside the sequence
IF _coordinatorState = AxoCoordinatorStates#Running THEN
// Stepping is possible only in StepByStepMode
Expand Down Expand Up @@ -118,6 +119,7 @@ NAMESPACE AXOpen.Core
IF step.GetIsActive() AND (step.IsReady() OR step.IsDone() OR SteppingMode = eAxoSteppingMode#StepByStep) THEN
IF (SteppingMode = eAxoSteppingMode#Continous) THEN
step.Invoke();
THIS.GetContext().GetLogger().Log('Starts step :', AXOpen.Logging.eLogLevel#Verbose, step);
// Invoke the step in a case of step mode when StepIn Command is invoked
ELSIF (SteppingMode = eAxoSteppingMode#StepByStep) THEN
IF StepIn.Execute() THEN
Expand All @@ -140,6 +142,7 @@ NAMESPACE AXOpen.Core
IF SUPER.Execute() THEN
IF THIS.InvalidContext(_step) THEN RETURN; END_IF;
IF _coordinatorState = AxoCoordinatorStates#Running THEN
THIS.GetContext().GetLogger().Log('Step done :', AXOpen.Logging.eLogLevel#Verbose, _step);
_step.DoneWhen(_step.IsBusy());
_step.SetIsActive(FALSE);
CurrentOrder := CurrentOrder + ULINT#1;
Expand All @@ -158,8 +161,9 @@ NAMESPACE AXOpen.Core
END_VAR
IF SUPER.Execute() THEN
IF THIS.InvalidContext(RequestedStep) THEN RETURN; END_IF;
IF RequestedStep.GetStepOrder() <> ULINT#0 AND
IF RequestedStep.GetStepOrder() <> ULINT#0 AND
_coordinatorState = AxoCoordinatorStates#Running THEN
THIS.GetContext().GetLogger().Log('Step request to step :', AXOpen.Logging.eLogLevel#Verbose, RequestedStep);
_step.DoneWhen(_step.IsBusy());
_step.SetIsActive(FALSE);
CurrentOrder := RequestedStep.GetStepOrder();
Expand All @@ -185,6 +189,7 @@ NAMESPACE AXOpen.Core
// Finalize the StepIn Command in a case of step mode
StepIn.DoneWhen(SteppingMode = eAxoSteppingMode#StepByStep);
THIS.OnCompleteSequence();
THIS.GetContext().GetLogger().Log('Sequence completed :', AXOpen.Logging.eLogLevel#Verbose, THIS);
END_IF;
END_IF;
END_METHOD
Expand Down
1 change: 1 addition & 0 deletions src/core/ctrl/src/AxoCoordination/AxoStep/AxoStep.st
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ NAMESPACE AXOpen.Core
VAR_INPUT
Active : BOOL;
END_VAR
IF(NOT THIS.IsActive AND Active) THEN THIS.GetContext().GetLogger().Log('At step:', AXOpen.Logging.eLogLevel#Verbose, THIS); END_IF;
IsActive := Active;
END_METHOD

Expand Down
11 changes: 6 additions & 5 deletions src/core/ctrl/src/AxoLogger/AxoLogger.st
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
USING AXOpen.Core;
USING AXOpen.Core;

NAMESPACE AXOpen.Logging
/// <summary>
Expand Down Expand Up @@ -32,18 +33,18 @@ NAMESPACE AXOpen.Logging
METHOD PUBLIC Log
VAR_INPUT
_message : STRING[80];
_level : eLogLevel;
_sender : IAxoObject;
_level : eLogLevel;
_sender : IAxoObject;
END_VAR

IF(_level >= THIS.MinimumLevel) THEN
IF(Carret > 100) THEN
Carret := 0;
END_IF;

LogEntries[Carret].Message := _message;
LogEntries[Carret].Level := _level;

IF(_sender <> NULL) THEN
LogEntries[Carret].Sender := _sender.GetIdentity();
END_IF;
Expand All @@ -52,7 +53,7 @@ NAMESPACE AXOpen.Logging
Carret := Carret + 1;
END_IF;
END_METHOD

/// <summary>
/// Log method that captures a message and logging level.
/// </summary>
Expand Down
21 changes: 10 additions & 11 deletions src/core/ctrl/src/AxoMessaging/Static/AxoMessenger.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ USING AXOpen.Core;
NAMESPACE AXOpen.Messaging.Static
{#ix-prop: public string MessageText }
{#ix-prop: public string Help }
CLASS AxoMessenger IMPLEMENTS AXOpen.Messaging.Static.IAxoMessageProperties
CLASS AxoMessenger EXTENDS AxoObject IMPLEMENTS AXOpen.Messaging.Static.IAxoMessageProperties
VAR PUBLIC
{#ix-attr:[ReadOnly()]}
IsActive : BOOL;
Expand All @@ -24,12 +24,12 @@ NAMESPACE AXOpen.Messaging.Static
{#ix-attr:[ReadOnly()]}
AcknowledgedBeforeFallen : BOOL;
{#ix-attr:[ReadOnly()]}
Acknowledged : LDATE_AND_TIME;
Acknowledged : LDATE_AND_TIME;
END_VAR

VAR PRIVATE
ActiveContextCount : ULINT;
Context : IAxoContext;
Context : IAxoContext;
END_VAR

METHOD PUBLIC Serve
Expand Down Expand Up @@ -63,7 +63,9 @@ NAMESPACE AXOpen.Messaging.Static
IF AXOpen.Core.IsNullContext(_object.GetContext()) THEN
RETURN;
END_IF;
THIS.Serve(_object.GetContext());
THIS.Initialize(_object);

THIS.Serve(_object.GetContext());
END_METHOD

METHOD PUBLIC Activate : AXOpen.Messaging.Static.IAxoMessageProperties
Expand All @@ -83,7 +85,7 @@ NAMESPACE AXOpen.Messaging.Static
Fallen := LDATE_AND_TIME#1970-01-01-00:00:00.000;
Acknowledged := LDATE_AND_TIME#1970-01-01-00:00:00.000;
WaitingForAcknowledge := FALSE;
Context.GetLogger().Log('Risen', THIS.ToLogLevel(_category));
Context.GetLogger().Log('Risen', THIS.ToLogLevel(_category), THIS);
END_IF;

ActiveContextCount := Context.OpenCycleCount();
Expand All @@ -101,10 +103,7 @@ NAMESPACE AXOpen.Messaging.Static
VAR_INPUT
_messageCategory : eAxoMessageCategory;
END_VAR
VAR

END_VAR


CASE _messageCategory OF
eAxoMessageCategory#Trace :
ToLogLevel := eLogLevel#Verbose;
Expand Down Expand Up @@ -132,7 +131,6 @@ NAMESPACE AXOpen.Messaging.Static

END_METHOD


METHOD PUBLIC ActivateOnCondition : AXOpen.Messaging.Static.IAxoMessageProperties
VAR_INPUT
_condition : BOOL;
Expand Down Expand Up @@ -176,7 +174,8 @@ NAMESPACE AXOpen.Messaging.Static
IF IsActive THEN
IsActive := FALSE;
ActiveContextCount := ULINT#0;
Fallen := Context.GetRtc().NowUTC();
Fallen := Context.GetRtc().NowUTC();
Context.GetLogger().Log('Fallen', eLogLevel#Information, THIS);
IF AcknowledgementRequired AND NOT AcknowledgedBeforeFallen THEN
WaitingForAcknowledge := TRUE;
END_IF;
Expand Down
Loading