@uoa/lambda-tracing 2.1.2 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ReleaseSteps.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Steps to release package to npm
2
2
  1. `npm login`
3
3
  2. `npm version <new version>`
4
- 3. Push to git to sync new tags
5
- 4. `npm publish --access=public --otp=<2FA code>`
4
+ 3. Update changelog.md & commit the changes
5
+ 4. Push to git to sync new tags
6
+ 5. `npm publish --access=public --otp=<2FA code>`
6
7
 
7
8
  # Testing locally before release
8
9
  1. `npm pack`
package/UoaLogger.ts ADDED
@@ -0,0 +1,103 @@
1
+ import winston, {Logger, LoggerOptions} from "winston";
2
+
3
+ /**
4
+ * Audit information to describe who is accessing a sensitive or confidential resource.
5
+ */
6
+ export interface AuditInformation {
7
+ /**
8
+ * Application name that groups different physical systems into a single logical group.
9
+ * For example, this may be the front end system name so that multiple backend system logs can be grouped together.
10
+ */
11
+ application?: string;
12
+ /**
13
+ * The ID of the user who is accessing the resource.
14
+ */
15
+ accessedBy: string;
16
+ /**
17
+ * The action taken on the resource.
18
+ */
19
+ action: 'read' | 'update' | 'create' | 'delete';
20
+ /**
21
+ * The ID of the owner of the resource information.
22
+ */
23
+ ownerId: string;
24
+ /**
25
+ * The type of resource accessed. For example, "application" or "enrolment".
26
+ * By convention this value should be singular.
27
+ */
28
+ resourceType: string;
29
+ /**
30
+ * The unique resource identifier. For example, the application number.
31
+ * This is not required if the resource identifier is the same as the owner.
32
+ */
33
+ resourceId?: string;
34
+ }
35
+
36
+ export class UoaLogger {
37
+ logger: Logger;
38
+
39
+ constructor(options: LoggerOptions) {
40
+ this.logger = winston.createLogger(options);
41
+ }
42
+
43
+ /**
44
+ * Function to log debug level messages.
45
+ * @param {string} message - Debug message.
46
+ */
47
+ public debug(message: string) {
48
+ this.logger.debug(message);
49
+ }
50
+
51
+ /**
52
+ * Function to log info level messages.
53
+ * @param {string} message - Information message.
54
+ */
55
+ public info(message: string) {
56
+ this.logger.info(message);
57
+ }
58
+
59
+ /**
60
+ * Function to log audit level messages.
61
+ * @param {AuditInformation} auditInformation - Audit Information object containing relevant details.
62
+ * @param {string=} message - Audit message (optional).
63
+ */
64
+ public audit(auditInformation: AuditInformation, message?: string): void {
65
+ // Initialize logMessage with mandatory fields
66
+ let logMessage: string =
67
+ `accessedBy:${auditInformation.accessedBy.replace(/\s/g, '')} ` +
68
+ `action:${auditInformation.action.toString().replace(/\s/g, '')} ` +
69
+ `owner:${auditInformation.ownerId.replace(/\s/g, '')} ` +
70
+ `resourceType:${auditInformation.resourceType.replace(/\s/g, '')}`;
71
+
72
+ // Add optional fields if they exist
73
+ if (auditInformation.application) {
74
+ logMessage = `application:${auditInformation.application.replace(/\s/g, '')} ` + logMessage;
75
+ }
76
+ if (auditInformation.resourceId) {
77
+ logMessage += ` resourceId:${auditInformation.resourceId.replace(/\s/g, '')}`;
78
+ }
79
+
80
+ // Append additional message if provided
81
+ if (message) {
82
+ logMessage += ` ${message}`;
83
+ }
84
+
85
+ this.logger.log("audit", logMessage);
86
+ }
87
+
88
+ /**
89
+ * Function to log warn level messages.
90
+ * @param {string} message - Warn message.
91
+ */
92
+ public warn(message: string) {
93
+ this.logger.warn(message);
94
+ }
95
+
96
+ /**
97
+ * Function to log error level messages.
98
+ * @param {string} message - Error message.
99
+ */
100
+ public error(message: string) {
101
+ this.logger.error(message);
102
+ }
103
+ }
package/changelog.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.2.1
4
+ - Fix formatting in readme
5
+
6
+ ## 2.2.0
7
+ - Added audit level to logger
8
+ - The logger debug, info, warn, and error functions now require a string input
9
+
3
10
  ## 2.1.2
4
11
  - Updated XML response parsing to include attribute tags
5
12
 
@@ -0,0 +1,63 @@
1
+ import { Logger, LoggerOptions } from "winston";
2
+ /**
3
+ * Audit information to describe who is accessing a sensitive or confidential resource.
4
+ */
5
+ export interface AuditInformation {
6
+ /**
7
+ * Application name that groups different physical systems into a single logical group.
8
+ * For example, this may be the front end system name so that multiple backend system logs can be grouped together.
9
+ */
10
+ application?: string;
11
+ /**
12
+ * The ID of the user who is accessing the resource.
13
+ */
14
+ accessedBy: string;
15
+ /**
16
+ * The action taken on the resource.
17
+ */
18
+ action: 'read' | 'update' | 'create' | 'delete';
19
+ /**
20
+ * The ID of the owner of the resource information.
21
+ */
22
+ ownerId: string;
23
+ /**
24
+ * The type of resource accessed. For example, "application" or "enrolment".
25
+ * By convention this value should be singular.
26
+ */
27
+ resourceType: string;
28
+ /**
29
+ * The unique resource identifier. For example, the application number.
30
+ * This is not required if the resource identifier is the same as the owner.
31
+ */
32
+ resourceId?: string;
33
+ }
34
+ export declare class UoaLogger {
35
+ logger: Logger;
36
+ constructor(options: LoggerOptions);
37
+ /**
38
+ * Function to log debug level messages.
39
+ * @param {string} message - Debug message.
40
+ */
41
+ debug(message: string): void;
42
+ /**
43
+ * Function to log info level messages.
44
+ * @param {string} message - Information message.
45
+ */
46
+ info(message: string): void;
47
+ /**
48
+ * Function to log audit level messages.
49
+ * @param {AuditInformation} auditInformation - Audit Information object containing relevant details.
50
+ * @param {string=} message - Audit message (optional).
51
+ */
52
+ audit(auditInformation: AuditInformation, message?: string): void;
53
+ /**
54
+ * Function to log warn level messages.
55
+ * @param {string} message - Warn message.
56
+ */
57
+ warn(message: string): void;
58
+ /**
59
+ * Function to log error level messages.
60
+ * @param {string} message - Error message.
61
+ */
62
+ error(message: string): void;
63
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UoaLogger = void 0;
7
+ const winston_1 = __importDefault(require("winston"));
8
+ class UoaLogger {
9
+ constructor(options) {
10
+ this.logger = winston_1.default.createLogger(options);
11
+ }
12
+ /**
13
+ * Function to log debug level messages.
14
+ * @param {string} message - Debug message.
15
+ */
16
+ debug(message) {
17
+ this.logger.debug(message);
18
+ }
19
+ /**
20
+ * Function to log info level messages.
21
+ * @param {string} message - Information message.
22
+ */
23
+ info(message) {
24
+ this.logger.info(message);
25
+ }
26
+ /**
27
+ * Function to log audit level messages.
28
+ * @param {AuditInformation} auditInformation - Audit Information object containing relevant details.
29
+ * @param {string=} message - Audit message (optional).
30
+ */
31
+ audit(auditInformation, message) {
32
+ // Initialize logMessage with mandatory fields
33
+ let logMessage = `accessedBy:${auditInformation.accessedBy.replace(/\s/g, '')} ` +
34
+ `action:${auditInformation.action.toString().replace(/\s/g, '')} ` +
35
+ `owner:${auditInformation.ownerId.replace(/\s/g, '')} ` +
36
+ `resourceType:${auditInformation.resourceType.replace(/\s/g, '')}`;
37
+ // Add optional fields if they exist
38
+ if (auditInformation.application) {
39
+ logMessage = `application:${auditInformation.application.replace(/\s/g, '')} ` + logMessage;
40
+ }
41
+ if (auditInformation.resourceId) {
42
+ logMessage += ` resourceId:${auditInformation.resourceId.replace(/\s/g, '')}`;
43
+ }
44
+ // Append additional message if provided
45
+ if (message) {
46
+ logMessage += ` ${message}`;
47
+ }
48
+ this.logger.log("audit", logMessage);
49
+ }
50
+ /**
51
+ * Function to log warn level messages.
52
+ * @param {string} message - Warn message.
53
+ */
54
+ warn(message) {
55
+ this.logger.warn(message);
56
+ }
57
+ /**
58
+ * Function to log error level messages.
59
+ * @param {string} message - Error message.
60
+ */
61
+ error(message) {
62
+ this.logger.error(message);
63
+ }
64
+ }
65
+ exports.UoaLogger = UoaLogger;
package/dist/logging.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const UoaB3Propagator_1 = require("./UoaB3Propagator");
4
4
  const tracing_1 = require("./tracing");
5
+ const UoaLogger_1 = require("./UoaLogger");
5
6
  const winston = require('winston');
6
7
  const moment = require('moment');
7
8
  const path = require('path');
@@ -10,8 +11,9 @@ const defaultLogPattern = '%date [%thread] %level %class - [[[%traceId,%spanId,%
10
11
  const uoaLogLevels = {
11
12
  error: 0,
12
13
  warn: 1,
13
- info: 2,
14
- debug: 3
14
+ audit: 2,
15
+ info: 3,
16
+ debug: 4
15
17
  };
16
18
  const uoaLoggingFormat = function (callingModule) {
17
19
  return winston.format.printf((logInfo) => {
@@ -58,7 +60,7 @@ function getLogReplacementValues(callingModule, logInfo) {
58
60
  return logReplacements;
59
61
  }
60
62
  module.exports = function (callingModule) {
61
- return winston.createLogger({
63
+ return new UoaLogger_1.UoaLogger({
62
64
  levels: uoaLogLevels,
63
65
  transports: [
64
66
  new winston.transports.Console({
package/logging.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {B3_INFO_KEY, B3_TRACE_ID_LENGTH_KEY} from "./UoaB3Propagator";
2
2
  import {getTraceInfoHeader} from "./tracing";
3
+ import {UoaLogger} from "./UoaLogger";
3
4
 
4
5
  const winston = require('winston');
5
6
  const moment = require('moment');
@@ -10,8 +11,9 @@ const defaultLogPattern = '%date [%thread] %level %class - [[[%traceId,%spanId,%
10
11
  const uoaLogLevels = {
11
12
  error: 0,
12
13
  warn: 1,
13
- info: 2,
14
- debug: 3
14
+ audit: 2,
15
+ info: 3,
16
+ debug: 4
15
17
  }
16
18
 
17
19
  const uoaLoggingFormat = function(callingModule: NodeModule) {
@@ -68,7 +70,7 @@ function getLogReplacementValues(callingModule: NodeModule, logInfo: any): Map<s
68
70
  }
69
71
 
70
72
  module.exports = function (callingModule: NodeModule) {
71
- return winston.createLogger({
73
+ return new UoaLogger({
72
74
  levels: uoaLogLevels,
73
75
  transports: [
74
76
  new winston.transports.Console({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uoa/lambda-tracing",
3
- "version": "2.1.2",
3
+ "version": "2.2.1",
4
4
  "description": "Library for logging & distributed tracing in UoA Lambda projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,7 +36,7 @@
36
36
  "@opentelemetry/sdk-trace-node": "^1.8.0",
37
37
  "fast-xml-parser": "^4.3.4",
38
38
  "moment": "^2.29.3",
39
- "winston": "^3.7.2"
39
+ "winston": "^3.13.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^17.0.35",
package/readme.md CHANGED
@@ -47,14 +47,15 @@ logger.info('Hello Logger!');
47
47
 
48
48
  **Logging Levels**
49
49
 
50
- At UoA, we have four logging levels available to use. Ordered by decreasing priority, these are:
50
+ At UoA, we have five logging levels available to use. Ordered by decreasing priority, these are:
51
51
 
52
- |Level| Logger usage |
53
- |-----|--------------------|
54
- |ERROR|```logger.error()```|
55
- |WARN |```logger.warn()``` |
56
- |INFO |```logger.info()``` |
57
- |DEBUG|```logger.debug()```|
52
+ | Level | Logger usage |
53
+ |-------|----------------------|
54
+ | ERROR | ```logger.error()``` |
55
+ | WARN | ```logger.warn()``` |
56
+ | AUDIT | ```logger.audit()``` |
57
+ | INFO | ```logger.info()``` |
58
+ | DEBUG | ```logger.debug()``` |
58
59
 
59
60
  By default, any log at the `INFO` level or higher will be logged. However, this can be changed by adding another
60
61
  environment variable `loggingLevel` in the lambda properties map of the environment.yml file. The value of this
@@ -68,6 +69,7 @@ lambda:
68
69
  ```
69
70
  logger.debug('Will not be logged');
70
71
  logger.info('Will not be logged');
72
+ logger.audit({...}, 'Will not be logged');
71
73
  logger.warn('Will be logged');
72
74
  logger.error('Will be logged');
73
75
  ```
@@ -89,16 +91,43 @@ lambda:
89
91
  ```
90
92
  Valid logging pattern placeholders are as follows:
91
93
 
92
- |Placeholder|Replacement value|Example value|
93
- |-----------|-----------------|-----|
94
- |%date|Date time when the message is logged in ISO8601 format|2022-05-29T21:31:11.250Z|
95
- |%thread|Unused, this is only present in the default pattern to match with UoA logging standards. Value will always be ```-```|-|
96
- |%level|Log level|INFO|
97
- |%class|The module which logged the message|src.handle-service|
98
- |%traceId|Unique Id for the request|5c0c783c965a684842608f10422fdf2c|
99
- |%spanId|Unique Id for the current lambda invocation|6a8b025511ac1191|
100
- |%info|Extra information to help with filtering the logs|usefulCode=12345|
101
- |%message|The logged message|Hello Logger!|
94
+ | Placeholder | Replacement value | Example value |
95
+ |-------------|-----------------------------------------------------------------------------------------------------------------------|----------------------------------|
96
+ | %date | Date time when the message is logged in ISO8601 format | 2022-05-29T21:31:11.250Z |
97
+ | %thread | Unused, this is only present in the default pattern to match with UoA logging standards. Value will always be ```-``` | - |
98
+ | %level | Log level | INFO |
99
+ | %class | The module which logged the message | src.handle-service |
100
+ | %traceId | Unique Id for the request | 5c0c783c965a684842608f10422fdf2c |
101
+ | %spanId | Unique Id for the current lambda invocation | 6a8b025511ac1191 |
102
+ | %info | Extra information to help with filtering the logs | usefulCode=12345 |
103
+ | %message | The logged message | Hello Logger! |
104
+
105
+ **Audit Logs**
106
+
107
+ All logger functions **_except_** `logger.audit()` take a single string as the message to be logged. The audit() function
108
+ takes an `AuditInformation` object as a parameter. A second `message` parameter of type string is optional. Using the
109
+ values passed in the `AuditInformation` parameter, the audit log message will be standardised so that logstash can
110
+ correctly ingest and send the logs to the _uoa-app-audit-logs-*_ index on Kibana.
111
+
112
+ The `AuditInformation` parameter has the below required properties:
113
+
114
+ | Property | Type | Description |
115
+ |--------------|--------------------------------------------------------|----------------------------------------------------|
116
+ | application (optional) | string | Application name that groups different physical systems into a single logical group. For example, this may be the front end system name so that multiple backend system logs can be grouped together. |
117
+ | action | 'read' &#124; 'update' &#124; 'create' &#124; 'delete' | The CRUD action being performed on the resource. |
118
+ | resourceId (optional) | string | The ID of the resource being actioned upon. |
119
+ | resourceType | string | The name/type of the resource being actioned upon. |
120
+ | ownerId | string | The ID of the owner of the resource information. |
121
+ | accessedBy | string | The ID of the person/system accessing the resource. |
122
+
123
+ Calling the `logger.audit()` function as below:
124
+ ```typescript
125
+ logger.audit({application: "applicationName", action: "read", resourceId: "123456789", resourceType: "personalDetails", accessedBy: "upi1234", ownerId: "upi5678"}, "Additional useful info");
126
+ ```
127
+ Will produce the following log message:
128
+ ```text
129
+ 2024-04-12T00:58:05.321Z [-] AUDIT src.controller.person-controller - [[[TraceId,SpanId,Info]]] application:applicationName accessedBy:upi1234 action:read owner:upi5678 resourceType:personalDetails resourceId:123456789 Additional useful info
130
+ ```
102
131
 
103
132
  ### Distributed Tracing
104
133
  There are two headers that can be passed in API calls to your lambda project using this library: ```X-B3-TraceId``` and ```X-B3-Info```.