The LogObjectType is an ObjectType that defines an instance that is used to collect log messages and make them available to a Client. An instance of LogObject can contain LogRecords that were generated internally. It can also contain LogRecords that result from Events that have a ConditionClassId or ConditionSubClassId of LogEntryConditionClassType that are reported by the Object on which the LogObject instance is declared (see 6). The LogObject can also generate Events for LogRecords that were generated internally.

The underlying storage of LogRecords is not defined. The records could be stored as part of an EventHistory, the records could be stored in a SYSLOG or OpenTelemetry or in some application specific manner (See Annex A for illustrations)

Although this specification does not define how data is stored, a requirement to persist LogRecords (i.e. LogRecords will be retained following a restart) is defined in a ConformanceUnit and may be added to a Profile.

The LogObject exposes a Method that allows a Client to retrieve the LogRecords. This Method does not provide complex filtering, only a time range and Severity. It also provides a mask that allows the Client to select which fields in a LogRecord to return and a maximum number of records to return. Some instances of a LogObject may optionally expose HistoricalEvents which would allow a more complex Event retrieval filter (see HistoricalEvent retrieval in OPC 10000-11).

The LogObjectType is illustrated in Figure 3.

image006.png

Figure 3 – LogObjectType illustration

The LogObjectType is formally defined in Table 1. The LogRecord structure that is returned by the GetRecords Method is described in 5.4.

Table 1 – LogObjectType definition

Attribute

Value

BrowseName

0:LogObjectType

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the 0:BaseObjectType defined in OPC 10000-5

0:HasComponent

Method

0:GetRecords

Defined in 5.3

M

0:HasProperty

Variable

0:MaxRecords

0:UInt32

0:PropertyType

O

0:HasProperty

Variable

0:MaxStorageDuration

0:Duration

0:PropertyType

O

0:HasProperty

Variable

0:MinimumSeverity

0:UInt16

0:PropertyType

O

ConformanceUnits

LogObject Base

Optional MaxRecords defines the maximum number of records in a buffer associated with this LogObject. When this maximum is reached, a new log record will trigger the deletion of the oldest record. If this Variable is not provided, then there is no Server published limit on the log buffer. Zero is an invalid value for MaxRecords. The LogRecord Structure is defined in 5.4.

Optional MaxStorageDuration defines the maximum time period that the LogObject will buffer log entries in the LogObject. Records that are older than the maximum duration may be deleted. If this Variable is not provided than no maximum duration is configured. Zero is an invalid duration. In the case of persistent storage, on startup a number of records may be deleted, depending on the duration of the downtime for the application.

The two maximum settings are used to limit the storage requirements for a Server. MaxRecords is typically a hard limit while MaxStorageDuration is more a soft limit in that LogRecords may be retained past the MaxStorageDuration if space allows. If MaxRecords is exceeded before MaxStorageDuration, the system should generate a LogOverflowEventType warning Event indicating an overflow of LogRecords (see 6.4).

The MinimumSeverity describes the minimum Severity associated with a LogRecord that is stored. LogRecords with a Severity that is less then this number will not be stored in this LogObject. If omitted, there is no restriction on the Severity associated with LogRecords that are stored. This number shall be between 0 and 1000, any other number is illegal. Servers can allow this value to be written. The Severity is only checked when a LogRecord is being generated, a change to the value does not affect the records that are already stored.

This Method allows a Client to retrieve LogRecords from the LogObject.

The signature of the Method is described below, and the arguments are described in Table 2.

Signature

GetRecords (

[in] 0:DateTime StartTime,

[in] 0:DateTime EndTime,

[in] 0:UInt32 MaxReturnRecords,

[in] 0:UInt16 MinimumSeverity,

[in] 0:LogRecordMask RequestMask,

[in] 0:ByteString ContinuationPointIn,

[out] LogRecordsDataTypeResults,

[out] 0:ByteString ContinuationPointOut

);

Table 2 – GetRecords Method arguments

Argument

Description

StartTime

The time associated with the first LogRecord returned in the Results array, or if no there is no LogRecord at this time, then the first LogRecord returned will have the time closest to, but greater than StartTime.

EndTime

The time associated with the last LogRecord. EndTime must be equal to or greater than StartTime. No records more recent then EndTime are returned. If there are no LogRecords at EndTime, then the most recent record before EndTime is the last record in the Results array.

MaxReturnRecords

The maximum number of LogRecords to be returned, 0 indicates that no limit is specified. If this limit is specified then the LogRecords will start at StartTime, but may end before EndTime if the limit is reached. This shall result in a ContinuationPointOut being generated by the Server. On subsequent calls with the continuation point, the remaining LogRecords can be retrieved.

MinimumSeverity

The minimum Severity (all LogRecords with a Severity equal to this number or greater are returned).

RequestMask

The RecordMask indicates which optional fields in the LogRecord Structure are to be returned, if they are available. The LogRecordMask is defined in 5.7.

ContinuationPointIn

An opaque identifier provided by the Server from a previous call to GetRecords. This input parameter shall be null on an initial call to GetRecords. If not all records were returned on a previous call, the ContinuationPointOut can be provided to continue the retrieval of records. If a ContinuationPointIn is passed in, all other input arguments shall be the same as provided on the call that returned the ContinuationPointOut. If any of the input parameters are changed, the Server can ignore the updated parameters, it can detect any changes to the parameters and report an error or it can process the request as if it was a new request. If the Client specifies a ContinuationPointIn that is no longer valid, then the Server shall return a Bad_ContinuationPointInvalid error.

Results

Is a structure (see 5.9) that contains an array of the LogRecord Structure (see 5.4). The LogRecords shall be returned in chronological order from oldest to newest.

ContinuationPointOut

An opaque identifier that is used if the number of records to be returned is too large to be returned in a single response or if the Server requires the Client to call again. When this parameter is not used, its value is null. This identifier can be used to continue the retrieval of LogRecords in subsequent calls.

StartTime and EndTime together form the range in which LogRecords are returned. If StartTime equals EndTime, then only LogRecord(s) that have the provided time are returned. If EndTime is earlier than StartTime, then the error Bad_InvalidParameter is returned.

Severity is a number between 1 and 1000 inclusive, a number outside of this range will result in the error Bad_InvalidParameter (see Table 5 for additional details).

A ContinuationPointOut shall be generated if the number of records to return between StartTime and EndTime is larger than what can be returned in a single Method call. It can also be returned due to an internal error or issue by the Server.

The GetRecords Method representation in the AddressSpace is formally defined in Table 3.

Table 3 – GetRecords Method AddressSpace definition

Attribute

Value

BrowseName

0:GetRecords

References

Node Class

BrowseName

DataType

TypeDefinition

Other

0:HasProperty

Variable

0:InputArguments

0:Argument[]

0:PropertyType

M

0:HasProperty

Variable

0:OutputArguments

0:Argument[]

0:PropertyType

M

ConformanceUnits

LogObject Base

This structured DataType describes the required information in a LogRecord. An array of this record type is returned in the LogObject GetRecords Method call.

The structure is formally defined in Table 4.

Table 4 – LogRecord structure

Name

Type

Description

Optional

LogRecord

Structure

Subtype of Structure defined in OPC 10000-5

Time

0:DateTime

Time associated with this record.

False

Severity

0:UInt16

Is a number between 1 and 1000 inclusive and corresponds to the range provided in the OPC UA BaseEventType (see OPC 10000-3). Additional details for mapping of the severity defined for OPC BaseEvents to LogRecords is described in Table 5.

False

EventType

0:NodeId

Describes the specific type of Event. It corresponds to the EventType field defined in BaseEventType.

If AdditionalData is provided then an EventType should be provided.

True

SourceNode

0:NodeId

Identifies the Node this record originated from. If the LogRecord is not related to a specific Node then this shall be set to a null NodeId.. Additional rules may be defined by other specifications that utilize the LogObject.

True

SourceName

0:String

Provides a description of the source of the LogRecord, this could be the string-part of the BrowseName of the SourceNode.

True

Message

0:LocalizedText

Shall describe the issue that is being represented in the LogRecord.

False

TraceContext

0:TraceContextDataType

This structure is used to correlate records inside of a Server along with corelating records between other Servers and Clients. The TraceContextDataType is described in 5.5.3.

True

AdditionalData

0:NameValuePair[]

Additional data for the log entry. This field contains the additional event fields of an LogEvent.

True

Severity ranges for Alarms and alerts are discussed further in OPC 10000-9. Diagnostic information typically has a Severity below the Alarm threshold of 400. Table 5 provides the Severity ranges that shall be used for LogRecords.

Table 5 – LogRecord Severity Mapping

Range Name

Severity Range

Diagnostics classification

Emergency

401 – 1000

Critical errors - errors that are fatal. This range can also be associated with Alarms.

Alert

300 – 400

Alerts are errors that are not raised to the Alarm level, but require some actions, typically by maintenance staff and could be recorded as part of an Alarm system.

Critical

251 – 300

Errors that can affect the overall process and need to be addressed.

Error

201 – 250

Errors related to important actions that were taken on the Server. They typically do not affect the overall process.

Warning

151 – 200

Warnings are issues that should be noted, but are not failures.

Notice

101-150

This level is typically used for significant or unusual successful actions that are taken on a Server.

Information

51-100

General Information related to an application.

Debug

1-50

Low level tracing information that can be used to debug the flow of an application.

The LogRecord representation in the AddressSpace is formally defined in Table 6

Table 6 – LogRecord definition

Attribute

Value

BrowseName

LogRecord

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the 0:Structure defined in OPC 10000-5

ConformanceUnits

LogObject Base

The LogContext contains information required to trace distributed transactions or requests made to a distributed system. Such a trace may produce multiple log messages in one OPC UA Application and/or multiple log messages across multiple OPC UA Applications.

The TraceId is a unique identifier for a trace. Once assigned it never changes for that trace. If log messages for a given trace are across applications, they have the same TraceId.

A span represents a unit of work or operation. Spans are the building blocks of traces. A span is local to an OPC UA Application. The SpanId is a unique identifier assigned by an OPC UA Application for a local span in a trace. Spans can be nested. The ParentSpanId provides the reference to the parent span. The ParentSpanId is used to build a tree of spans inside a trace. If a nested span is created, the SpanId of the parent is used as ParentSpanId in the new child span.

At the very start (the root span) there is no ParentSpanId, only a new SpanId. This would be the base of a tree. See C.1 for additional discussion on SpanId and ParentSpanId.

The SpanContextDataType Structure is defined in Table 7. It defines a TraceId and SpanId. This Structure can be passed between Clients and Servers (see 5.5.4).

Table 7 – SpanContextDataType

Name

Type

Description

SpanContextDataType

Structure

Subtype of Structure defined in OPC 10000-5

TraceId

0:Guid

A unique identifier assigned to a trace.

SpanId

0:UInt64

Identifier for a span in a trace. 0 is an invalid value for a SpanId. The value shall be unique within a ParentSpanId within an Application.

The SpanContextDataType representation in the AddressSpace is formally defined in Table 8

Table 8 – SpanContextDataType definition

Attribute

Value

BrowseName

SpanContextDataType

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the 0:Structure defined in OPC 10000-5

ConformanceUnits

LogObject TraceContext

The TraceContextDataType Structure is defined in Table 9. This structure is a subtype of the SpanContextDataType and is used in the LogRecord. It extends the SpanContextDataType Structure adding two additional fields. The ParentSpanId (together with the SpanId) allows for the creation of a tree of related Log Records. The ParentIdentifier can be used to provide context information related to the parent.

Table 9 – TraceContextDataType

Name

Type

Description

TraceContextDataType

Structure

Subtype of SpanContextDataType defined in 5.5.2

ParentSpanId

0:UInt64

The identifier of the parent span. The value is 0 for a root span.

ParentIdentifier

0:String

If the parent span is from another OPC UA Application, the ParentIdentifier contains the ApplicationUri of the other OPC UA Application.

If the parent span is an internal span, the ParentIdentifier shall be null or empty.

If the ParentSpanId is 0, the ParentIdentifier shall be null or empty.

The TraceContextDataType representation in the AddressSpace is formally defined in Table 10.

Table 10 – TraceContextDataType definition

Attribute

Value

BrowseName

TraceContextDataType

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the SpanContextDataType defined in 5.5.2

ConformanceUnits

LogObject TraceContext

If the Server is to be part of a Client trace, the Client passes the SpanContextDataType structure to a Server.

The SpanContextDataType Structure, defined in Table 7, is passed in the RequestHeader of any OPC UA Service call. The SpanContextDataType is transported with the AdditionalParametersType in the AdditionalHeader field of the RequestHeader (see OPC 10000-4). The Key for the parameter is “SpanContext and the Value is the SpanContextDataType Structure.

If a Server receives the optional AdditionalHeader, it uses the provided SpanConextDataType Structure when generating any LogRecords that are generated related to the Service invocation that provided the AdditionalHeader. It is possible that lower level functionality that is invoked as part of the Service call, may not have access to the provided AdditionalHeader, in which case it maybe omitted.

Inside the Server, the SpanId from the RequestHeader is used as ParentId for the LogContext structure defined in Table 9.

The NameValuePair structure is formally defined in Table 11. This structure has a Name field that is a name that is associated with the value that is reported in the second field. The Value may be of any DataType. Specifications may define standard names that are used to transport specific values that are to be included in the LogRecord as AdditionalData.

Table 11 – NameValuePair structure

Name

Type

Description

NameValuePair

Structure

Subtype of Structure defined in OPC 10000-5

Name

String

The name of the value.

Value

BaseDataType

The value associated with the name.

The NameValuePair Structure representation in the AddressSpace is formally defined in Table 12

Table 12 – NameValuePair definition

Attribute

Value

BrowseName

NameValuePair

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the 0:Structure defined in OPC 10000-5

ConformanceUnits

LogObject AdditionalData

The LogRecordMask is formally defined in Table 13. It indicates which of the optional fields that may be available in a LogRecord are to be returned by GetRecords.

Table 13 – LogRecordMask Structure

Value

Bit No.

Description

EventType

0

Indicates if the EventType is returned in the LogRecords if available.

SourceNode

1

Indicates if the SourceNode is returned in the LogRecords if available.

SourceName

2

Indicates if the SourceName is returned in the LogRecords if available.

TraceContext

3

Indicates if the TraceContext is returned in the LogRecords if available.

AdditionalData

4

Indicates if the AdditionalData is returned in the LogRecords if available.

The LogRecordMask representation in the AddressSpace is formally defined in Table 14

Table 14 – LogRecordMask definition

Attribute

Value

BrowseName

LogRecordMask

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of UInt32 defined in OPC 10000-3

HasProperty

Variable

OptionSetValues

LocalizedText []

PropertyType

ConformanceUnits

LogObject Base

When generating LogRecords it is important that a context be associated with each LogRecord. This context information can be used to show a relationship between various LogRecords in a Server as well as relationships between LogRecords that are in different Servers. This context information is stored in the TraceContext field in the record (see definition in 5.5.2). If a hierarchy of related LogRecords is to be created, SpanId and ParentSpanId fields shall be used. When a function in a Server invokes another function in the same Server or in another Server as part of the same TraceId, the lower level function shall promote the SpanId of the higher level to be the ParentSpanId in the called function and a new SpanId shall be generated in the called function. This daisy chain of SpanId to ParentSpanId will allow a tree to be created for the LogRecords.

image007.png

Figure 4 - TraceContext hierarchy example

Figure 4 provides an illustration of the LogRecords that could result from calls between two Applications that include TraceContext information. The first line is each table is a list of the fields in the comma-separated-value records. These field names correspond to the names used in the LogRecord structure.

The key points being illustrated for the hierarchy are the TraceId, SpandId, ParentSpanId and ParentIdentifier field, which are the last 4 items in each LogRecord entry. The TraceId is shown as the GUID and is constant for this illustration (it is one action from the Client/Server). Additional actions would result in separate TraceIds, but are not illustrated.

In the Client/Server there is no ParentIdentifier, since all action are internal to the Server. In the RemoteServer the ParentIdentifier indicates the Client/Server. The ParentIdentifier is the ApplicationUri of the Client that called into the Server. The ApplicationUri of the first Server is “Https:CM1…”( it has been truncated to allow it to fit in the example).

The SpanId and ParentSpanId shows where calls have been made. At the beginning of the first table, the ParentSpanId is zero, since this is the root SpanId (see Annex C for more explanation of SpanId). In the first table, when a sub function is called, the SpanId is promoted to the ParentSpanId and a new SpanId is generated (see the third LogRecord in the table).

The large arrow shows that the Client/Server calls into the RemoteServer twice. It passes in the TraceId and the SpanId on each call. The TraceId is the same, but the SpanId changes on each call.

The second table shows the LogRecords that are generated that resulted from the two innovations of the Method in the RemoteServer. The passed in SpanId becomes the ParentSpanId in the LogRecords and a new SpanId is generated. The RemoteServer also makes a call to a sub-function where the SpanId is promoted to the ParentSpanId.

This structured DataType is used as the return DataType in the LogObject GetRecords Method call.

The structure is formally defined in Table 15.

Table 15 – LogRecordsDataType structure

Name

Type

Description

LogRecordsDataType

Structure

Subtype of Structure defined in OPC 10000-5

LogRecordArray

LogRecord[]

An array of LogRecords.

The LogRecordsDataType representation in the AddressSpace is formally defined in Table 16.

Table 16 – LogRecordsDataType definition

Attribute

Value

BrowseName

LogRecordsDataType

IsAbstract

False

References

NodeClass

BrowseName

DataType

TypeDefinition

Other

Subtype of the 0:Structure defined in OPC 10000-5

ConformanceUnits

LogObject Base

The LogObject can include information that maybe sensitive or include security related information. For LogObjects that contain security related information should not be made accessible to all users, but only to authorised users.

A LogObject can restrict a Client’s access to the GetRecords Method using standard OPC UA security features. This all or nothing approach can work well if multiple LogObjects are defined in a Server and security related information is collected in a separate LogObject. It becomes more problematic if a single LogObject collects a mixture of security related information and non-security related information.

LogObjects should implement permissions similar to what Event systems implement. In Event systems each Event has permissions assigned to it, in a LogObject each LogRecord can have permissions assigned to it. These permissions can be used to determine if a LogRecord should be returned to the Client that is invoking the GetRecords Method.