@extk/logger-cloudwatch 0.1.0

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/README.md ADDED
@@ -0,0 +1,97 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/extk%E2%9A%A1-expressive-blue?style=for-the-badge&labelColor=1a1a2e&color=4361ee">
4
+ <img alt="extk/expressive logo" src="https://img.shields.io/badge/extk%E2%9A%A1-expressive-blue?style=for-the-badge&labelColor=f0f0f0&color=4361ee">
5
+ </picture>
6
+ </p>
7
+
8
+ # @extk/logger-cloudwatch
9
+
10
+ Opinionated winston loggers with AWS CloudWatch support.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm install @extk/logger-cloudwatch
16
+ ```
17
+
18
+ ## Loggers
19
+
20
+ ### `getCloudwatchLogger(opts)`
21
+
22
+ Streams JSON logs to AWS CloudWatch. Each process gets its own log stream named `YYYY-MM-DD/pid-<pid>`. Creates the log group if it doesn't exist.
23
+
24
+ ```ts
25
+ import { getCloudwatchLogger } from '@extk/logger-cloudwatch';
26
+
27
+ const logger = getCloudwatchLogger({
28
+ aws: {
29
+ region: 'us-east-1',
30
+ logGroup: '/my-app/production',
31
+ credentials: {
32
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
33
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
34
+ },
35
+ },
36
+ });
37
+
38
+ logger.info('Request handled', { userId: 123 });
39
+ ```
40
+
41
+ Optionally attach a context function to merge fields into every log entry:
42
+
43
+ ```ts
44
+ const logger = getCloudwatchLogger({
45
+ aws: { ... },
46
+ contextFn: (info) => {
47
+ info['service'] = 'payments';
48
+ return info;
49
+ },
50
+ });
51
+ ```
52
+
53
+ | Option | Description |
54
+ |-------------------|-------------|
55
+ | `aws.region` | AWS region |
56
+ | `aws.logGroup` | CloudWatch log group name |
57
+ | `aws.credentials` | `accessKeyId` + `secretAccessKey` |
58
+ | `contextFn` | Optional transform to add fields to every entry |
59
+
60
+ ### `getConsoleLogger()`
61
+
62
+ Logs to stdout. Intended for development or simple services.
63
+
64
+ ```ts
65
+ import { getConsoleLogger } from '@extk/logger-cloudwatch';
66
+
67
+ const logger = getConsoleLogger();
68
+ logger.info('Server started');
69
+ ```
70
+
71
+ ### `getFileLogger(name?)`
72
+
73
+ Writes to `./logs/<name>.log`. Cached — calling with the same name returns the same instance.
74
+
75
+ ```ts
76
+ import { getFileLogger } from '@extk/logger-cloudwatch';
77
+
78
+ const logger = getFileLogger('app');
79
+ logger.error(new Error('Something went wrong'));
80
+ ```
81
+
82
+ | Option | Default |
83
+ |--------|---------|
84
+ | `name` | `'app'` |
85
+ | Output | `./logs/<name>.log` |
86
+ | Level | `debug` |
87
+
88
+ ## Log format
89
+
90
+ Console and file loggers use a human-readable format:
91
+
92
+ ```
93
+ DD/MM/YYYY HH:mm:ss[LEVEL]: message
94
+ DD/MM/YYYY HH:mm:ss[ERROR]: Error: something\n at ... ← stack trace for errors
95
+ ```
96
+
97
+ CloudWatch receives structured JSON with `timestamp`, `level`, `message`, and any extra fields.
@@ -0,0 +1,19 @@
1
+ import winston from 'winston';
2
+
3
+ declare const getFileLogger: (name?: string) => winston.Logger;
4
+ declare const getConsoleLogger: () => winston.Logger;
5
+
6
+ type options = {
7
+ aws: {
8
+ region: string;
9
+ logGroup: string;
10
+ credentials: {
11
+ accessKeyId: string;
12
+ secretAccessKey: string;
13
+ };
14
+ };
15
+ contextFn?: winston.Logform.TransformFunction;
16
+ };
17
+ declare const getCloudwatchLogger: (opts: options) => winston.Logger;
18
+
19
+ export { getCloudwatchLogger, getConsoleLogger, getFileLogger };
@@ -0,0 +1,19 @@
1
+ import winston from 'winston';
2
+
3
+ declare const getFileLogger: (name?: string) => winston.Logger;
4
+ declare const getConsoleLogger: () => winston.Logger;
5
+
6
+ type options = {
7
+ aws: {
8
+ region: string;
9
+ logGroup: string;
10
+ credentials: {
11
+ accessKeyId: string;
12
+ secretAccessKey: string;
13
+ };
14
+ };
15
+ contextFn?: winston.Logform.TransformFunction;
16
+ };
17
+ declare const getCloudwatchLogger: (opts: options) => winston.Logger;
18
+
19
+ export { getCloudwatchLogger, getConsoleLogger, getFileLogger };
package/dist/index.js ADDED
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ getCloudwatchLogger: () => getCloudwatchLogger,
34
+ getConsoleLogger: () => getConsoleLogger,
35
+ getFileLogger: () => getFileLogger
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_winston3 = __toESM(require("winston"));
39
+ var import_winston_cloudwatch = __toESM(require("winston-cloudwatch"));
40
+
41
+ // ../../shared/src/loggers.ts
42
+ var import_winston2 = __toESM(require("winston"));
43
+
44
+ // ../../shared/src/common.ts
45
+ var import_winston = __toESM(require("winston"));
46
+ var defaultStringFormat = import_winston.default.format.combine(
47
+ import_winston.default.format.timestamp({ format: "DD/MM/YYYY HH:mm:ss" }),
48
+ import_winston.default.format.splat(),
49
+ import_winston.default.format.errors({ stack: true }),
50
+ import_winston.default.format.printf(({ level, message, timestamp, stack }) => `${timestamp}[${level.toUpperCase()}]: ${stack || message}`)
51
+ );
52
+ var consoleTransport = new import_winston.default.transports.Console({
53
+ handleExceptions: true
54
+ });
55
+
56
+ // ../../shared/src/loggers.ts
57
+ var createFileLogger = (filename) => import_winston2.default.createLogger({
58
+ format: defaultStringFormat,
59
+ transports: [
60
+ new import_winston2.default.transports.File({
61
+ filename: `./logs/${filename}.log`,
62
+ handleExceptions: true,
63
+ level: "debug"
64
+ })
65
+ ]
66
+ });
67
+ var loggerRegistry = {};
68
+ var getFileLogger = (name = "app") => {
69
+ if (!loggerRegistry[name]) {
70
+ loggerRegistry[name] = createFileLogger(name.toString());
71
+ }
72
+ return loggerRegistry[name];
73
+ };
74
+ var consoleLogger;
75
+ var getConsoleLogger = () => {
76
+ if (!consoleLogger) {
77
+ consoleLogger = import_winston2.default.createLogger({
78
+ format: defaultStringFormat,
79
+ transports: [consoleTransport]
80
+ });
81
+ }
82
+ return consoleLogger;
83
+ };
84
+
85
+ // src/index.ts
86
+ var getCloudwatchLogger = (opts) => {
87
+ const formats = [
88
+ import_winston3.default.format.timestamp(),
89
+ import_winston3.default.format.splat(),
90
+ import_winston3.default.format.errors({ stack: true })
91
+ ];
92
+ if (opts.contextFn) {
93
+ formats.push(import_winston3.default.format(opts.contextFn)());
94
+ }
95
+ return import_winston3.default.createLogger({
96
+ exitOnError: false,
97
+ format: import_winston3.default.format.combine(...formats),
98
+ transports: [
99
+ new import_winston_cloudwatch.default({
100
+ logGroupName: opts.aws.logGroup,
101
+ logStreamName: `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}/pid-${process.pid}`,
102
+ awsRegion: opts.aws.region,
103
+ awsAccessKeyId: opts.aws.credentials.accessKeyId,
104
+ awsSecretKey: opts.aws.credentials.secretAccessKey,
105
+ jsonMessage: true,
106
+ ensureLogGroup: true
107
+ })
108
+ ]
109
+ });
110
+ };
111
+ // Annotate the CommonJS export names for ESM import in node:
112
+ 0 && (module.exports = {
113
+ getCloudwatchLogger,
114
+ getConsoleLogger,
115
+ getFileLogger
116
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,79 @@
1
+ // src/index.ts
2
+ import winston3 from "winston";
3
+ import WinstonCloudWatch from "winston-cloudwatch";
4
+
5
+ // ../../shared/src/loggers.ts
6
+ import winston2 from "winston";
7
+
8
+ // ../../shared/src/common.ts
9
+ import winston from "winston";
10
+ var defaultStringFormat = winston.format.combine(
11
+ winston.format.timestamp({ format: "DD/MM/YYYY HH:mm:ss" }),
12
+ winston.format.splat(),
13
+ winston.format.errors({ stack: true }),
14
+ winston.format.printf(({ level, message, timestamp, stack }) => `${timestamp}[${level.toUpperCase()}]: ${stack || message}`)
15
+ );
16
+ var consoleTransport = new winston.transports.Console({
17
+ handleExceptions: true
18
+ });
19
+
20
+ // ../../shared/src/loggers.ts
21
+ var createFileLogger = (filename) => winston2.createLogger({
22
+ format: defaultStringFormat,
23
+ transports: [
24
+ new winston2.transports.File({
25
+ filename: `./logs/${filename}.log`,
26
+ handleExceptions: true,
27
+ level: "debug"
28
+ })
29
+ ]
30
+ });
31
+ var loggerRegistry = {};
32
+ var getFileLogger = (name = "app") => {
33
+ if (!loggerRegistry[name]) {
34
+ loggerRegistry[name] = createFileLogger(name.toString());
35
+ }
36
+ return loggerRegistry[name];
37
+ };
38
+ var consoleLogger;
39
+ var getConsoleLogger = () => {
40
+ if (!consoleLogger) {
41
+ consoleLogger = winston2.createLogger({
42
+ format: defaultStringFormat,
43
+ transports: [consoleTransport]
44
+ });
45
+ }
46
+ return consoleLogger;
47
+ };
48
+
49
+ // src/index.ts
50
+ var getCloudwatchLogger = (opts) => {
51
+ const formats = [
52
+ winston3.format.timestamp(),
53
+ winston3.format.splat(),
54
+ winston3.format.errors({ stack: true })
55
+ ];
56
+ if (opts.contextFn) {
57
+ formats.push(winston3.format(opts.contextFn)());
58
+ }
59
+ return winston3.createLogger({
60
+ exitOnError: false,
61
+ format: winston3.format.combine(...formats),
62
+ transports: [
63
+ new WinstonCloudWatch({
64
+ logGroupName: opts.aws.logGroup,
65
+ logStreamName: `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}/pid-${process.pid}`,
66
+ awsRegion: opts.aws.region,
67
+ awsAccessKeyId: opts.aws.credentials.accessKeyId,
68
+ awsSecretKey: opts.aws.credentials.secretAccessKey,
69
+ jsonMessage: true,
70
+ ensureLogGroup: true
71
+ })
72
+ ]
73
+ });
74
+ };
75
+ export {
76
+ getCloudwatchLogger,
77
+ getConsoleLogger,
78
+ getFileLogger
79
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@extk/logger-cloudwatch",
3
+ "version": "0.1.0",
4
+ "type": "commonjs",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "engines": {
19
+ "node": ">=22.0.0"
20
+ },
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "dependencies": {
26
+ "winston": "^3.11.0",
27
+ "winston-cloudwatch": "^6.3.0"
28
+ },
29
+ "license": "ISC",
30
+ "description": "AWS CloudWatch logger",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/sergeytangyan/extk-logger",
34
+ "directory": "packages/cloudwatch"
35
+ }
36
+ }