...
MDC | Group | Description | Applicable (per log file) | Marker Associations | Required? Y/N/C (C= context dependent) N = not required | Use Cases | Code References | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
UUID to track the processing of each client request across all the ONAP components involved in its processing | Y | |||||||||||||||||||
InvocationID | UUID correlates log entries relating to a single invocation of a single component | Y | ||||||||||||||||||
InstanceUUID | UUID to differentiate between multiple instances of the same (named) log writing service/application | Y | ||||||||||||||||||
ServiceName | The service inside the partner doing the call - includes API name | Y | ||||||||||||||||||
PartnerName | The URI that the caller used to make the call to the component that is logging the message. | Y | ||||||||||||||||||
StatusCode | This field indicates the high level status of the request - one of (COMPLETE, ERROR) | Y | ||||||||||||||||||
ResponseCode | This field contains application-specific error codes. | Y | ||||||||||||||||||
ResponseDescription | This field contains a human readable description of the ResponseCode. | Y | ||||||||||||||||||
Severity | OPS specific Use/Map existing? https://www.slf4j.org/api/org/apache/commons/logging/Log.html ENUM is Logging level by default aligned with the reported log level - one of INFO/TRACE/DEBUG/WARN/ERROR/FATAL By default - align this severity with the reported log level (optionally a way to map actual level from reported level if required) | Y | ||||||||||||||||||
ServerFQDN | This field contains the Virtual Machine (VM) Fully Qualified Domain Name (FQDN) The VM FQDN if the server is virtualized. Otherwise , it contains the the host name of the logging component. Best effort (ip, fqdn) (previously covered by removed "Server" field) redundancy between clientIP, server, virtualServer name is OK - and helpfull for runtime OPS/Hybrid envs superceedes virtualServerName Report what is in the http header Discussion: roll all 3 fqdn, hostname or ip into one field - do we ever need two of the 3 fields concurrently? TODO: Verify what is also available from a filebeat agent when it exists | Y | ClientIPAddress | This field contains the requesting remote client application’s IP address if known. Otherwise this field can be empty. We don't differentiate between inside/outside ONAP for the IP - this supports hybrid environments Derived from the system redundancy between clientIP, server, virtualServer name is OK - and helpfull for runtime OPS/Hybrid envs Discussion: do we need both ip and fqdn fields? Report what is in the http header | Y | EntryTimestamp (previously BeginTimestamp) | C | InvokeTimestamp (prevously EndTimestamp) | Timestamp on invocation start Context dependent on whether part of an INVOKE marker metrics needs invoke | C | TargetEntity | It contains the name of the ONAP component or sub-component, or external entity, at which the operation activities captured in this metrics log record is invoked. Example: SDC-BE | C | TargetServiceName | It contains the name of the API or operation activities invoked (name on the remote/target application) at the TargetEntity. Example: Class name of rest endpoint Discussion: on building call graph vs human readable single line - keep for human readable Used as valuable URI - to annnote invoke marker Review in terms of Marker-INVOKE - possiblly add INVOKE-return - to filter reporting TBD: Coverage by log file type (debug, trace, ...) TBD: cover off discussion on reducing log files to two (DEBUG/rest) for C* release | C | TargetElement | VNF/PNF context dependent - on CRUD operations of VNF/PNFs The IDs that need to be covered with the above Attributes are - VNF_ID OR VNFC_ID : (Unique identifier for a VNF asset that is being instantiated or that would generate an alarms) - VSERVER_ID OR VM_ID (or vmid): (Unique identified for a virtual server or virtual machine on which a Control Loop action is usually taken on, or that is installed as part of instantiation flow) - PNF : (What is the Unique identifier used within ONAP) | C |
Logging
Via SLF4J:
Code Block | ||||
---|---|---|---|---|
| ||||
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
// ...
final Logger logger = LoggerFactory.getLogger(this.getClass());
MDC.put("SomeUUID", UUID.randomUUID().toString());
try {
logger.info("This message will have a UUID-valued 'SomeUUID' MDC attached.");
// ...
}
finally {
MDC.clear();
} |
Y | |||||||
ClientIPAddress | This field contains the requesting remote client application’s IP address if known. Otherwise empty. | Y | |||||
EntryTimestamp | UTC Date-time that processing activities being logged begins - if part of an ENTRY marker | C | |||||
InvokeTimestamp | Timestamp on invocation start - if part of an INVOKE marker | C | |||||
TargetEntity | It contains the name of the ONAP component or sub-component, or external entity, at which the operation activities captured in this metrics log record is invoked. Example: SDC-BE | C | |||||
TargetServiceName | It contains the name of the API or operation activities invoked (name on the remote/target application) at the TargetEntity. Example: Class name of rest endpoint Discussion: on building call graph vs human readable single line - keep for human readable Used as valuable URI - to annnote invoke marker Review in terms of Marker-INVOKE - possiblly add INVOKE-return - to filter reporting TBD: Coverage by log file type (debug, trace, ...) TBD: cover off discussion on reducing log files to two (DEBUG/rest) for C* release | C | |||||
TargetElement | VNF/PNF context dependent - on CRUD operations of VNF/PNFs The IDs that need to be covered with the above Attributes are - VNF_ID OR VNFC_ID : (Unique identifier for a VNF asset that is being instantiated or that would generate an alarms) - VSERVER_ID OR VM_ID (or vmid): (Unique identified for a virtual server or virtual machine on which a Control Loop action is usually taken on, or that is installed as part of instantiation flow) - PNF : (What is the Unique identifier used within ONAP) | C |
Logging
Via SLF4J:
Code Block | ||||
---|---|---|---|---|
| ||||
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
// ...
final Logger logger = LoggerFactory.getLogger(this.getClass());
MDC.put("SomeUUID", UUID.randomUUID().toString());
try {
logger.info("This message will have a UUID-valued 'SomeUUID' MDC attached.");
// ...
}
finally {
MDC.clear();
} |
EELF doesn't directly support MDCs, but its default provider (where com.att.eelf.configuration.SLF4jWrapper is the configured EELF provider)normally logs via SLF4J, and SLF4J will receive any MDC that is set:
Code Block | ||||
---|---|---|---|---|
| ||||
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
// ...
final EELFLogger logger = EELFManager.getInstance().getLogger(this.getClass());
MDC.put("SomeUUID", UUID.randomUUID().toString());
try {
logger.info("This message will have a UUID-valued 'SomeUUID' MDC attached.");
// ...
}
finally {
MDC.clear();
} |
Serializing
Output of MDCs must ensure that:
- All reported MDCs are logged with both name AND value. Logging output should not treat any MDCs as special.
- All MDC names and values are escaped.
Escaping in Logback configuration can be achieved with:
Code Block | ||||
---|---|---|---|---|
| ||||
%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} |
MDC - RequestID
This is often referred to by other names, including "Transaction ID", and one of several (pre-standardization) REST header names including X-ECOMP-RequestID and X-ONAP-RequestID.
ONAP logging uses a universally unique "RequestID" value in log records to track the processing of each client request across all the ONAP components involved in its processing. RequestID be propagated across all interfaces, not just REST Interfaces.
This value:
- Is logged as a RequestID MDC.
- Is propagated between components in REST calls as an X-TransactionID HTTP header.
Receiving the X-TransactionID will vary by component according to APIs and frameworks. In generalEELF doesn't directly support MDCs, but its default provider (where com.att.eelf.configuration.SLF4jWrapper is the configured EELF provider)normally logs via SLF4J, and SLF4J will receive any MDC that is set:
Code Block | ||||
---|---|---|---|---|
| ||||
import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManagerjavax.ws.rs.core.HttpHeaders; // ... final EELFLoggerHttpHeaders loggerheaders = EELFManager.getInstance().getLogger(this.getClass()); MDC.put("SomeUUID", UUID.randomUUID().toString()); try { logger.info("This message will have a UUID-valued 'SomeUUID' MDC attached.// ... String txId = headers.getRequestHeaders().getFirst("X-TransactionID"); // ... } finallyif (StringUtils.isBlank(txId)) { txId MDC.clear= UUID.randomUUID().toString(); } |
Serializing
Output of MDCs must ensure that:
- All reported MDCs are logged with both name AND value. Logging output should not treat any MDCs as special.
- All MDC names and values are escaped.
MDC.put("RequestID", txID); |
Setting the X-TransactionID likewise will vary. For exampleEscaping in Logback configuration can be achieved with:
Code Block | ||||
---|---|---|---|---|
| ||||
%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} |
MDC - RequestID
This is often referred to by other names, including "Transaction ID", and one of several (pre-standardization) REST header names including X-ECOMP-RequestID and X-ONAP-RequestID.
ONAP logging uses a universally unique "RequestID" value in log records to track the processing of each client request across all the ONAP components involved in its processing. RequestID be propagated across all interfaces, not just REST Interfaces.
This value:
- Is logged as a RequestID MDC.
- Is propagated between components in REST calls as an X-TransactionID HTTP header.
Receiving the X-TransactionID will vary by component according to APIs and frameworks. In general:
Code Block | ||||
---|---|---|---|---|
| ||||
import javax.ws.rs.core.HttpHeaders;
// ...
final HttpHeaders headers = ...;
// ...
String txId = headers.getRequestHeaders().getFirst("X-TransactionID");
if (StringUtils.isBlank(txId)) {
txId = UUID.randomUUID().toString();
}
MDC.put("RequestID", txID); |
Setting the X-TransactionID likewise will vary. For example:
Code Block | ||||
---|---|---|---|---|
| ||||
final String txID = MDC.get("RequestID");
HttpURLConnection cx = ...;
// ...
cx.setRequestProperty("X-TransactionID", txID); |
MDC - InvocationID
InvocationID is similar to RequestID, but where RequestID correlates records relating a single, top-level invocation of ONAP as it traverses many systems, InvocationID correlates log entries relating to a single invocation of a single component. Typically this means via REST, but in certain cases an InvocationID may be allocated without a new invocation, e.g. when a request is retried.
RequestID and InvocationID allow an execution graph to be derived. This requires that:
- The relationship between RequestID and InvocationID is reported.
- The relationship between caller and recipient is reported for each invocation.
The proposed approach is that:
- Callers:
- Issue a new, unique InvocationID UUID for each downstream call they make.
- Log the new InvocationID, indicating the intent to invoke:
- With Markers INVOKE, and SYNCHRONOUS if the invocation is synchronous.
- With their own InvocationID still set as an MDC.
- Pass the InvocationID as an X-InvocationID REST header.
- Invoked components:
- Retrieve the InvocationID from REST headers upon invocation, or generate a UUID default.
- Set the InvocationID MDC.
- Write a log entry with the Marker ENTRY. (In EELF this will be to the AUDIT log).
- Act as per Callers in all downstream requests.
- Write a log entry with the Marker EXIT upon return. (In EELF this will be to the METRIC log).
- Unset all MDCs on exit.
That seems onerous, but:
...
final String txID = MDC.get("RequestID");
HttpURLConnection cx = ...;
// ...
cx.setRequestProperty("X-TransactionID", txID); |
MDC - InvocationID
InvocationID is similar to RequestID, but where RequestID correlates records relating a single, top-level invocation of ONAP as it traverses many systems, InvocationID correlates log entries relating to a single invocation of a single component. Typically this means via REST, but in certain cases an InvocationID may be allocated without a new invocation, e.g. when a request is retried.
RequestID and InvocationID allow an execution graph to be derived. This requires that:
- The relationship between RequestID and InvocationID is reported.
- The relationship between caller and recipient is reported for each invocation.
The proposed approach is that:
- Callers:
- Issue a new, unique InvocationID UUID for each downstream call they make.
- Log the new InvocationID, indicating the intent to invoke:
- With Markers INVOKE, and SYNCHRONOUS if the invocation is synchronous.
- With their own InvocationID still set as an MDC.
- Pass the InvocationID as an X-InvocationID REST header.
- Invoked components:
- Retrieve the InvocationID from REST headers upon invocation, or generate a UUID default.
- Set the InvocationID MDC.
- Write a log entry with the Marker ENTRY. (In EELF this will be to the AUDIT log).
- Act as per Callers in all downstream requests.
- Write a log entry with the Marker EXIT upon return. (In EELF this will be to the METRIC log).
- Unset all MDCs on exit.
That seems onerous, but:
- It's only a few calls.
- It can be largely abstracted in the case of EELF logging.
MDC - InstanceUUID
If known, this field contains a universally unique identifier used to differentiate between multiple instances of the same (named) log writing service/application. Its value is set at instance creation time (and read by it, e.g., at start/initialization time from the environment). This value should be picked up by the component instance from its configuration file and subsequently used to enable differentiation of log records created by multiple, locally load balanced ONAP component or subcomponent instances that are otherwise identically configured.
Handles parallel threads or running across a load balanced set of microservices - for identification.
MDC - PartnerName
This field should contain the name of the client application user agent or user invoking the API. The identification of the entity that made the request being served. For a serving API that is authenticating the request, this should be the authenticated username or equivalent (e.g. a userid or a mechid).
For example SDC-BE instead of just SDC for the overall pods
This is often used for heuristic analysis to identify invocations between ONAP individual ONAP components. Its value has never been clearly stipulated, so a common problem has been a lack of consistency.
There is no clear consensus, but:
- Use the short name of your component, e.g. xyzdriver. (try to incorporate both levels - the container name and the pod the container is in within the kubernetes deployment)
- Values should be human-readable.
- Values should be fine-grained enough to disambiguate subcomponents where it's likely to matter. This is subjective.
- Be consistent: your component should ALWAYS report same value.
Real-life examples include MSO, bpmnclient, BPELClient, (all of which are reported by SO), openECOMP (SDNC), vid (VID!) etc. (See the problem?)
Usage overlaps with InvocationID, which doesn't mean PartnerName gets retired, but which might mean it serves a more descriptive purpose. (Since it hasn't proven to be a great way of generating a call graph).
MDC - ServiceName
The URI that the caller used to make the call to the component that is logging the message.
For EELF Audit log records that capture API requests, this field contains the name of the API invoked at the component creating the record (e.g., Layer3ServiceActivateRequest).
For EELF Audit log records that capture processing as a result of receipt of a message, this field should contain the name of the module that processes the message.
Usage is the same for indexable logs.
MDC - StatusCode
This field indicates the high level status of the request. It must have the value COMPLETE when the request is successful and ERROR when there is a failure.
Discussion: status/response/severity relationship
status = global, response below is app specific
Ability to render severity-like line in a non-debug log
MDC - ResponseCode
This field contains application-specific error codes. For consistency, common error categorizations should be used.
MDC - Severity
OPS specific
Use/Map existing https://www.slf4j.org/api/org/apache/commons/logging/Log.html
ENUM is INFO/TRACE/DEBUG/WARN/ERROR/FATAL
By default - align this severity with the reported log level
(optionally a way to map actual level from reported level if required)
MDC - ServerFQDN
This field contains the Virtual Machine (VM) Fully Qualified Domain Name (FQDN) if the server is virtualized. Otherwise, it contains the host name of the logging component.
Best effort (ip, fqdn)
(previously covered by removed "Server" field)
redundancy between clientIP, server, virtualServer name is OK - and helpfull for runtime OPS/Hybrid envs
superceedes virtualServerName
Report what is in the http header
Discussion: roll all 3 fqdn, hostname or ip into one field - do we ever need two of the 3 fields concurrently?
TODO: Verify what is also available from a filebeat agent when it exists
MDC - ClientIPAddress
(previously BeginTimestamp)
This field contains the requesting remote client application’s IP address if known. Otherwise this field can be empty.
We don't differentiate between inside/outside ONAP for the IP - this supports hybrid environments
Derived from the system
redundancy between clientIP, server, virtualServer name is OK - and helpfull for runtime OPS/Hybrid envs
Discussion: do we need both ip and fqdn fields?
Report what is in the http header
MDC - EntryTimestamp
Date-time that processing activities being logged begins. The value should be represented in UTC and formatted per ISO 8601, such as “2015-06-03T13:21:58+00:00”. The time should be shown with the maximum resolution available to the logging component (e.g., milliseconds, microseconds) by including the appropriate number of decimal digits. For example, when millisecond precision is available, the date-time value would be presented as, as “2015-06-03T13:21:58.340+00:00”.
Context dependent on whether part of an ENTRY marker
Audit requires this field
MDC - InvokeTimestamp
(prevously EndTimestamp)
Timestamp on invocation start.
Context dependent on whether part of an INVOKE marker
metrics needs this field
...
MDC - InstanceUUID
If known, this field contains a universally unique identifier used to differentiate between multiple instances of the same (named) log writing service/application. Its value is set at instance creation time (and read by it, e.g., at start/initialization time from the environment). This value should be picked up by the component instance from its configuration file and subsequently used to enable differentiation of log records created by multiple, locally load balanced ONAP component or subcomponent instances that are otherwise identically configured.
Handles parallel threads or running across a load balanced set of microservices - for identification.
MDC - PartnerName
This field should contain the name of the client application user agent or user invoking the API. The identification of the entity that made the request being served. For a serving API that is authenticating the request, this should be the authenticated username or equivalent (e.g. a userid or a mechid).
For example SDC-BE instead of just SDC for the overall pods
This is often used for heuristic analysis to identify invocations between ONAP individual ONAP components. Its value has never been clearly stipulated, so a common problem has been a lack of consistency.
There is no clear consensus, but:
- Use the short name of your component, e.g. xyzdriver. (try to incorporate both levels - the container name and the pod the container is in within the kubernetes deployment)
- Values should be human-readable.
- Values should be fine-grained enough to disambiguate subcomponents where it's likely to matter. This is subjective.
- Be consistent: your component should ALWAYS report same value.
Real-life examples include MSO, bpmnclient, BPELClient, (all of which are reported by SO), openECOMP (SDNC), vid (VID!) etc. (See the problem?)
Usage overlaps with InvocationID, which doesn't mean PartnerName gets retired, but which might mean it serves a more descriptive purpose. (Since it hasn't proven to be a great way of generating a call graph).
MDC - ServiceName
The URI that the caller used to make the call to the component that is logging the message.
For EELF Audit log records that capture API requests, this field contains the name of the API invoked at the component creating the record (e.g., Layer3ServiceActivateRequest).
For EELF Audit log records that capture processing as a result of receipt of a message, this field should contain the name of the module that processes the message.
Usage is the same for indexable logs.
MDC - StatusCode
This field indicates the high level status of the request. It must have the value COMPLETE when the request is successful and ERROR when there is a failure.
Discussion: status/response/severity relationship
status = global, response below is app specific
Ability to render severity-like line in a non-debug log
MDC - ResponseCode
This field contains application-specific error codes. For consistency, common error categorizations should be used.
MDCs - the Rest
Other MDCs are logged in a wide range of contexts.
...