aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 44ea353c64ca38d7bf5d08d90fe2acbcac8d4f59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*-
 * ============LICENSE_START=======================================================
 * Common Logging Library
 * ================================================================================
 * Copyright (C) 2017 AT&T Intellectual Property. All rights
 * 						reserved.
 * ================================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============LICENSE_END=========================================================
 */

# Common Logging Library

The common logging library provides a single library that can be used by any microservice to produce logs.  
An abstraction layer is provided which exposes a public API to the microservices and shields them from the underlying implementation.

The current version of the library is backed by an implementation which wraps the EELF Logging framework, however, the intent is that other logging implementations could be substituted in the future without impacting the public API used by the microservice clients.

---

## Getting Started

### Making The Library Available To Your Microservice
In order to make the logging library available to your microservice, include the following dependency in your service's pom.xml:


    <!-- Common logging framework -->		
    <dependency>
        <groupId>org.openecomp.aai.logging-service</groupId>
        <artifactId>common-service</artifactId>
        <version>1.0.0</version>
    </dependency>


### Getting a Logger
There are three classes of _logger_ provided by the logging library:
* Standard logger - Used to generate most typical log statements.
* Audit logger - Used specifically to generate audit logs.
* Metrics logger - Used specifically to generate metrics logs.

In order to generate log statements, your code needs to acquire an instance of whichever *Logger* type that you need.  This is accomplished by requesting a *Logger* from the *LoggerFactory*

    Logger logger        = LoggerFactory.getInstance().getLogger( {my logger name} ); 
    Logger auditLogger   = LoggerFactory.getInstance().getAuditLogger( {my logger name} );
    Logger metricsLogger = LoggerFactory.getInstance().getMetricsLogger( {my logger name} );
    
where *{my logger name}* should be replaced with whatever name you want assigned to your logger instance.


### Log Statement Templates
The current version of the logging library is backed by the EELF Logging Framework.  This provides the ability to create log statement templates with arguments to be filled in at runtime.

**IMPORTANT:** When creating an enumerated class for message keys using the Common Logging Library, the class must implement `LogMessageEnum` and not `EELFResolvableErrorEnum` as detailed in the wiki link.

### Generating Basic Log Statements
Log statements can be generated at the following log levels:  **DEBUG**, **TRACE** **INFO**, **WARNING** and **ERROR** as follows:

    // Note, see the next section for a description of how to set the 'fields' argument.
    
    // Debug Level Logs. 
    logger.debug("Some debug message")
    logger.debug(MyMsgEnum.A_DEBUG_MSG, fields, "arg1", "arg2"...) 
	
    // Trace Level Logs.
    logger.trace(MyMsgEnum.A_TRACE_MSG, fields, "arg1", "arg2"...)
    
    // Info Level Logs.
    logger.info(MyMsgEnum.AN_INFO_MSG, fields, "arg1", "arg2"...)
    logger.info(MyMsgEnum.AN_INFO_MSG, fields, "a status string", a_status_code, "arg1", "arg2"...)
    logger.info(MyMsgEnum.AN_INFO_MSG, fields, "a status string", a_status_code, an_MDC_override, "arg1"...)
    
    // Warning Level Logs.    
    logger.warn(MyMsgEnum.A_WARNING_MSG, "arg1", "arg2"...)
    
    // Error Level Logs.
    logger.error(MyMsgEnum.AN_ERROR_MSG, "arg1", "arg2"...)

### Standardized Log Fields
There are a number of standard fields which the client may provide values for.  These fields will be automatically populated with the supplied values, in fixed positions within the generated log string.  

The client may pass values for these fields by populating a _LogFields_ object with _field name_/_value_ pairs as illustrated in the following example:

    LogFields fields = new LogFields()
                          .setField(LogLine.DefinedFields.CLIENT_IP, "1.2.3.4")
                          .setField(LogLine.DefinedFields.CLASS_NAME, "somename");
                           
In the logging examples in the previous section, the _fields_ argument, which we glossed over, would be set it this manner.  

The following fields are currently defined as settable by the client:
                         
        STATUS_CODE,           // High level success or failure of the request  (COMPLETE or ERROR)
        RESPONSE_CODE,         // Application-specific error code
        RESPONSE_DESCRIPTION,  // Human readable description of the application specific response code
        INSTANCE_UUID,         // universally unique identifier used to differentiate between multiple 
                               // instances of the same (named), log writing component
        SEVERITY,              // 0, 1, 2, 3  
        SERVER_IP,             // The logging component host server’s IP address  
        CLIENT_IP,             // Requesting remote client application’s IP address
        CLASS_NAME,            // This is the name of the class that has caused the log record to be created
        PROCESS_KEY,
        TARGET_SVC_NAME,       // External API/operation activities invoked on TargetEntity
        TARGET_ENTITY,         // Component or subcomponent invoked for this operation.
        CUSTOM_1,              // For whatever custom use the client determines.
        CUSTOM_2,              // For whatever custom use the client determines.
        CUSTOM_3,              // For whatever custom use the client determines.
        CUSTOM_4;              // For whatever custom use the client determines.
                           
### The Mapped Diagnostic Context
The _Mapped Diagnostic Context_ or MDC is a tool to help distinguish interleaved log output from different sources.  It lets the application thread place information in a diagnostic context that can later be retrieved by the logging components. 

#### Initializing the _MDC Context_
Application threads may initialize their MDC Context according to the following pattern:

	MDCContext.initialize({transaction id}, {service name}, {service instance}, {partner name} {client address});
	
Once initialized, the values stored in the _MDC Context_ will be used by the logger to auto populate the relevant fields in the standard log statement.

#### Supported Fields
The logging library makes use of a number of 'known' fields in the _MDC Context_.  These field names are exposed as static variables by the _MDCContext_ class:

    MDCContext.MDC_REQUEST_ID
    MDCContext.MDC_SERVER_FQDN
    MDCContext.MDC_SERVICE_NAME
    MDCContext.MDC_PARTNER_NAME
    MDCContext.MDC_START_TIME
    MDCContext.MDC_REMOTE_HOST
    MDCContext.MDC_SERVICE_INSTANCE_ID
    MDCContext.MDC_CLIENT_ADDRESS

If values are assigned to any of these fields, then they will be automatically inserted into the appropriate fields in the standard log statement generated by the logger, although it is not *required* that they be set.
	 
#### Overriding the Contents of the _MDC Context_
In certain situations, it is useful for the application thread to override or insert a value into one of the _MDC Context_ fields on a one-time basis when invoking the _logger_ (a good example is passing time stamp data to a metrics logger).

The following example illustrates how to achieve this:

    public void doSomeOperation() {
    
        // Instantiate a new MDCOverride object.
        MDCOverride override = new MDCOverride();
        
        // Grab the current time to use later for metrics calculations.
        long startTimeInMs = System.currentTimeMillis();
        
        // ...and add it as an attribute to our MDC Override 
        // object.
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");   
        override.addAttribute(MDCContext.MDC_START_TIME, formatter.format(startTimeInMs));
                
        // do a bunch of really important stuff...
        
        // Finally, invoke a metrics logger, passing in our instance of the
        // MDCOverride object.
        metricsLogger.info(MyMsgEnum.A_LOG_CODE, 
                           a_status_code,
                           override,
                           an_argument,
                           another_argument); 
    }