@oneminutelogs/nestjs 1.0.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 +151 -0
- package/dist/OneMinuteLogsInterceptor.d.ts +9 -0
- package/dist/OneMinuteLogsInterceptor.js +66 -0
- package/dist/OneMinuteLogsModule.d.ts +9 -0
- package/dist/OneMinuteLogsModule.js +47 -0
- package/dist/OneMinuteLogsService.d.ts +28 -0
- package/dist/OneMinuteLogsService.js +69 -0
- package/dist/configs/index.d.ts +4 -0
- package/dist/configs/index.js +9 -0
- package/dist/core/createLogger.d.ts +37 -0
- package/dist/core/createLogger.js +88 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +27 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/index.js +2 -0
- package/dist/types/log.d.ts +4 -0
- package/dist/types/log.js +2 -0
- package/dist/types/metrics.d.ts +1 -0
- package/dist/types/metrics.js +2 -0
- package/dist/types/security.d.ts +1 -0
- package/dist/types/security.js +2 -0
- package/dist/types/track.d.ts +1 -0
- package/dist/types/track.js +2 -0
- package/dist/utils/getLogs.d.ts +26 -0
- package/dist/utils/getLogs.js +25 -0
- package/dist/utils/getStream.d.ts +21 -0
- package/dist/utils/getStream.js +25 -0
- package/dist/utils/transport.d.ts +63 -0
- package/dist/utils/transport.js +185 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# @oneminutelogs/nestjs
|
|
2
|
+
|
|
3
|
+
The official NestJS SDK for [OneMinuteLogs](https://oneminutelogs.com).
|
|
4
|
+
|
|
5
|
+
This package provides a seamless integration with NestJS, including a Global Module, Service for manual logging, and an Interceptor for automatic request logging.
|
|
6
|
+
|
|
7
|
+
**Official Documentation:** [oneminutestack.com/docs/nestjs](https://oneminutestack.com/docs/nestjs)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Global Module**: Initialize once, use everywhere via dependency injection.
|
|
12
|
+
- **Interceptor**: Automatically logs every HTTP request with duration, status, and metadata.
|
|
13
|
+
- **Type-Safe Service**: injectable `OneMinuteLogsService` with all typed log methods (`info`, `error`, `audit`, etc.).
|
|
14
|
+
- **Async Configuration**: Support for `forRootAsync` to load config from `ConfigService`.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @oneminutelogs/nestjs
|
|
20
|
+
# or
|
|
21
|
+
yarn add @oneminutelogs/nestjs
|
|
22
|
+
# or
|
|
23
|
+
pnpm add @oneminutelogs/nestjs
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Import Module
|
|
29
|
+
|
|
30
|
+
Import `OneMinuteLogsModule` in your root `AppModule`.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { Module } from "@nestjs/common";
|
|
34
|
+
import { OneMinuteLogsModule } from "@oneminutelogs/nestjs";
|
|
35
|
+
|
|
36
|
+
@Module({
|
|
37
|
+
imports: [
|
|
38
|
+
OneMinuteLogsModule.forRoot({
|
|
39
|
+
apiKey: process.env.OML_API_KEY!,
|
|
40
|
+
appName: "my-nestjs-service",
|
|
41
|
+
environment: process.env.NODE_ENV || "development"
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
export class AppModule {}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Automatic Request Logging
|
|
49
|
+
|
|
50
|
+
Bind the `OneMinuteLogsInterceptor` globally in your `main.ts` or as a global provider.
|
|
51
|
+
|
|
52
|
+
**Option A: In `main.ts`**
|
|
53
|
+
```typescript
|
|
54
|
+
import { OneMinuteLogsInterceptor, OneMinuteLogsService } from "@oneminutelogs/nestjs";
|
|
55
|
+
|
|
56
|
+
async function bootstrap() {
|
|
57
|
+
const app = await NestFactory.create(AppModule);
|
|
58
|
+
|
|
59
|
+
const omlService = app.get(OneMinuteLogsService);
|
|
60
|
+
app.useGlobalInterceptors(new OneMinuteLogsInterceptor(omlService));
|
|
61
|
+
|
|
62
|
+
await app.listen(3000);
|
|
63
|
+
}
|
|
64
|
+
bootstrap();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Option B: As a Provider (Recommended)**
|
|
68
|
+
```typescript
|
|
69
|
+
import { Module } from "@nestjs/common";
|
|
70
|
+
import { APP_INTERCEPTOR } from "@nestjs/core";
|
|
71
|
+
import { OneMinuteLogsModule, OneMinuteLogsInterceptor } from "@oneminutelogs/nestjs";
|
|
72
|
+
|
|
73
|
+
@Module({
|
|
74
|
+
imports: [
|
|
75
|
+
OneMinuteLogsModule.forRoot({ /* ... */ }),
|
|
76
|
+
],
|
|
77
|
+
providers: [
|
|
78
|
+
{
|
|
79
|
+
provide: APP_INTERCEPTOR,
|
|
80
|
+
useClass: OneMinuteLogsInterceptor,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
})
|
|
84
|
+
export class AppModule {}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Manual Logging
|
|
88
|
+
|
|
89
|
+
Inject `OneMinuteLogsService` into any provider or controller.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { Injectable } from "@nestjs/common";
|
|
93
|
+
import { OneMinuteLogsService } from "@oneminutelogs/nestjs";
|
|
94
|
+
|
|
95
|
+
@Injectable()
|
|
96
|
+
export class AuthService {
|
|
97
|
+
constructor(private readonly logger: OneMinuteLogsService) {}
|
|
98
|
+
|
|
99
|
+
async validateUser(username: string) {
|
|
100
|
+
// Info log
|
|
101
|
+
await this.logger.info({ message: `Validating user ${username}` });
|
|
102
|
+
|
|
103
|
+
// Security Audit
|
|
104
|
+
await this.logger.audit({
|
|
105
|
+
message: "Login attempt",
|
|
106
|
+
security: {
|
|
107
|
+
auth_status: "pending",
|
|
108
|
+
user_id: username
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Async Configuration
|
|
116
|
+
|
|
117
|
+
If you need to load configuration asynchronously (e.g., from `@nestjs/config`), use `forRootAsync`.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { ConfigModule, ConfigService } from "@nestjs/config";
|
|
121
|
+
|
|
122
|
+
OneMinuteLogsModule.forRootAsync({
|
|
123
|
+
imports: [ConfigModule],
|
|
124
|
+
useFactory: async (configService: ConfigService) => ({
|
|
125
|
+
apiKey: configService.getOrThrow("OML_API_KEY"),
|
|
126
|
+
appName: configService.get("APP_NAME"),
|
|
127
|
+
}),
|
|
128
|
+
inject: [ConfigService],
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## API Reference
|
|
133
|
+
|
|
134
|
+
### OneMinuteLogsService
|
|
135
|
+
|
|
136
|
+
- `info(payload)`
|
|
137
|
+
- `error(payload)`
|
|
138
|
+
- `warning(payload)`
|
|
139
|
+
- `audit(payload)`
|
|
140
|
+
- `metric(payload)`
|
|
141
|
+
- `debug(payload)`
|
|
142
|
+
- `success(payload)`
|
|
143
|
+
- `send(payload)` (Generic)
|
|
144
|
+
- `get(filters)` (Query logs)
|
|
145
|
+
- `stream(filters)` (Stream logs)
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Support
|
|
150
|
+
|
|
151
|
+
If you have any questions or need assistance, please contact us at [contact@oneminutestack.com](mailto:contact@oneminutestack.com).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { OneMinuteLogsService } from "./OneMinuteLogsService.js";
|
|
4
|
+
export declare class OneMinuteLogsInterceptor implements NestInterceptor {
|
|
5
|
+
private readonly oml;
|
|
6
|
+
constructor(oml: OneMinuteLogsService);
|
|
7
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
|
|
8
|
+
private logRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OneMinuteLogsInterceptor = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const operators_1 = require("rxjs/operators");
|
|
15
|
+
const OneMinuteLogsService_js_1 = require("./OneMinuteLogsService.js");
|
|
16
|
+
let OneMinuteLogsInterceptor = class OneMinuteLogsInterceptor {
|
|
17
|
+
constructor(oml) {
|
|
18
|
+
this.oml = oml;
|
|
19
|
+
}
|
|
20
|
+
intercept(context, next) {
|
|
21
|
+
const req = context.switchToHttp().getRequest();
|
|
22
|
+
const res = context.switchToHttp().getResponse();
|
|
23
|
+
// Safety check for HTTP context
|
|
24
|
+
if (!req || !res) {
|
|
25
|
+
return next.handle();
|
|
26
|
+
}
|
|
27
|
+
const start = Date.now();
|
|
28
|
+
const method = req.method;
|
|
29
|
+
const url = req.originalUrl || req.url;
|
|
30
|
+
const ip = req.ip || req.socket?.remoteAddress;
|
|
31
|
+
const userAgent = req.get ? req.get("user-agent") : req.headers["user-agent"];
|
|
32
|
+
return next.handle().pipe((0, operators_1.tap)({
|
|
33
|
+
next: () => {
|
|
34
|
+
this.logRequest(method, url, res.statusCode, Date.now() - start, ip, userAgent);
|
|
35
|
+
},
|
|
36
|
+
error: (err) => {
|
|
37
|
+
// NestJS exception filters usually handle the response status specific logic
|
|
38
|
+
// But here we can catch the error flow
|
|
39
|
+
const status = err.status || 500;
|
|
40
|
+
this.logRequest(method, url, status, Date.now() - start, ip, userAgent, err.message);
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
logRequest(method, url, statusCode, duration, ip, userAgent, errorMessage) {
|
|
45
|
+
const isError = statusCode >= 400;
|
|
46
|
+
const logMethod = isError ? this.oml.error.bind(this.oml) : this.oml.info.bind(this.oml);
|
|
47
|
+
logMethod({
|
|
48
|
+
message: `${method} ${url} ${statusCode} - ${duration}ms${errorMessage ? ` [Error: ${errorMessage}]` : ""}`,
|
|
49
|
+
subsystem: "network",
|
|
50
|
+
metrics: {
|
|
51
|
+
duration,
|
|
52
|
+
statusCode,
|
|
53
|
+
method,
|
|
54
|
+
},
|
|
55
|
+
track: {
|
|
56
|
+
ip,
|
|
57
|
+
userAgent,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
exports.OneMinuteLogsInterceptor = OneMinuteLogsInterceptor;
|
|
63
|
+
exports.OneMinuteLogsInterceptor = OneMinuteLogsInterceptor = __decorate([
|
|
64
|
+
(0, common_1.Injectable)(),
|
|
65
|
+
__metadata("design:paramtypes", [OneMinuteLogsService_js_1.OneMinuteLogsService])
|
|
66
|
+
], OneMinuteLogsInterceptor);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DynamicModule } from "@nestjs/common";
|
|
2
|
+
import { LoggerConfig } from "./types/index.js";
|
|
3
|
+
export declare class OneMinuteLogsModule {
|
|
4
|
+
static forRoot(config: LoggerConfig): DynamicModule;
|
|
5
|
+
static forRootAsync(options: {
|
|
6
|
+
useFactory: (...args: any[]) => Promise<LoggerConfig> | LoggerConfig;
|
|
7
|
+
inject?: any[];
|
|
8
|
+
}): DynamicModule;
|
|
9
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var OneMinuteLogsModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.OneMinuteLogsModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const OneMinuteLogsService_js_1 = require("./OneMinuteLogsService.js");
|
|
13
|
+
let OneMinuteLogsModule = OneMinuteLogsModule_1 = class OneMinuteLogsModule {
|
|
14
|
+
static forRoot(config) {
|
|
15
|
+
return {
|
|
16
|
+
module: OneMinuteLogsModule_1,
|
|
17
|
+
providers: [
|
|
18
|
+
{
|
|
19
|
+
provide: OneMinuteLogsService_js_1.OML_CONFIG,
|
|
20
|
+
useValue: config,
|
|
21
|
+
},
|
|
22
|
+
OneMinuteLogsService_js_1.OneMinuteLogsService,
|
|
23
|
+
],
|
|
24
|
+
exports: [OneMinuteLogsService_js_1.OneMinuteLogsService],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
static forRootAsync(options) {
|
|
28
|
+
const providers = [
|
|
29
|
+
{
|
|
30
|
+
provide: OneMinuteLogsService_js_1.OML_CONFIG,
|
|
31
|
+
useFactory: options.useFactory,
|
|
32
|
+
inject: options.inject || [],
|
|
33
|
+
},
|
|
34
|
+
OneMinuteLogsService_js_1.OneMinuteLogsService,
|
|
35
|
+
];
|
|
36
|
+
return {
|
|
37
|
+
module: OneMinuteLogsModule_1,
|
|
38
|
+
providers,
|
|
39
|
+
exports: [OneMinuteLogsService_js_1.OneMinuteLogsService],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
exports.OneMinuteLogsModule = OneMinuteLogsModule;
|
|
44
|
+
exports.OneMinuteLogsModule = OneMinuteLogsModule = OneMinuteLogsModule_1 = __decorate([
|
|
45
|
+
(0, common_1.Global)(),
|
|
46
|
+
(0, common_1.Module)({})
|
|
47
|
+
], OneMinuteLogsModule);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LoggerConfig, LogPayload } from "./types/index.js";
|
|
2
|
+
export declare const OML_CONFIG = "OML_CONFIG";
|
|
3
|
+
export declare class OneMinuteLogsService {
|
|
4
|
+
private config;
|
|
5
|
+
private logger;
|
|
6
|
+
constructor(config: LoggerConfig);
|
|
7
|
+
/**
|
|
8
|
+
* Send a generic log payload.
|
|
9
|
+
*/
|
|
10
|
+
send(payload: LogPayload): Promise<void>;
|
|
11
|
+
info(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
12
|
+
error(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
13
|
+
warning(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
14
|
+
audit(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
15
|
+
metric(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
16
|
+
debug(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
17
|
+
success(payload: Omit<LogPayload, "type">): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Get historical logs.
|
|
20
|
+
*/
|
|
21
|
+
get(filters?: Record<string, any>): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Stream live logs.
|
|
24
|
+
*/
|
|
25
|
+
stream(filters: Record<string, any>): {
|
|
26
|
+
body: ReadableStream<Uint8Array> | null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.OneMinuteLogsService = exports.OML_CONFIG = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const createLogger_js_1 = require("./core/createLogger.js");
|
|
18
|
+
exports.OML_CONFIG = "OML_CONFIG";
|
|
19
|
+
let OneMinuteLogsService = class OneMinuteLogsService {
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
this.logger = (0, createLogger_js_1.createLogger)(config);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Send a generic log payload.
|
|
26
|
+
*/
|
|
27
|
+
async send(payload) {
|
|
28
|
+
return this.logger.send(payload);
|
|
29
|
+
}
|
|
30
|
+
async info(payload) {
|
|
31
|
+
return this.logger.info(payload);
|
|
32
|
+
}
|
|
33
|
+
async error(payload) {
|
|
34
|
+
return this.logger.error(payload);
|
|
35
|
+
}
|
|
36
|
+
async warning(payload) {
|
|
37
|
+
return this.logger.warning(payload);
|
|
38
|
+
}
|
|
39
|
+
async audit(payload) {
|
|
40
|
+
return this.logger.audit(payload);
|
|
41
|
+
}
|
|
42
|
+
async metric(payload) {
|
|
43
|
+
return this.logger.metric(payload);
|
|
44
|
+
}
|
|
45
|
+
async debug(payload) {
|
|
46
|
+
return this.logger.debug(payload);
|
|
47
|
+
}
|
|
48
|
+
async success(payload) {
|
|
49
|
+
return this.logger.success(payload);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get historical logs.
|
|
53
|
+
*/
|
|
54
|
+
async get(filters) {
|
|
55
|
+
return this.logger.get(filters);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Stream live logs.
|
|
59
|
+
*/
|
|
60
|
+
stream(filters) {
|
|
61
|
+
return this.logger.stream(filters);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
exports.OneMinuteLogsService = OneMinuteLogsService;
|
|
65
|
+
exports.OneMinuteLogsService = OneMinuteLogsService = __decorate([
|
|
66
|
+
(0, common_1.Injectable)(),
|
|
67
|
+
__param(0, (0, common_1.Inject)(exports.OML_CONFIG)),
|
|
68
|
+
__metadata("design:paramtypes", [Object])
|
|
69
|
+
], OneMinuteLogsService);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oneminutelogs – createLogger
|
|
3
|
+
*
|
|
4
|
+
* Summary:
|
|
5
|
+
* Factory that creates a typed logger backed by OMLTransport. Provides:
|
|
6
|
+
* - `send` for generic logging
|
|
7
|
+
* - type helpers: `info`, `error`, `metric`, `audit`, `warning`
|
|
8
|
+
* - passthrough `get` and `stream` to query historical logs and subscribe to live logs
|
|
9
|
+
*
|
|
10
|
+
* Package: @oneminutelogs/express
|
|
11
|
+
* Module: core/createLogger
|
|
12
|
+
*/
|
|
13
|
+
import type { LoggerConfig, LogPayload } from "../types/index.js";
|
|
14
|
+
/**
|
|
15
|
+
* Creates a logger bound to an OML transport.
|
|
16
|
+
*
|
|
17
|
+
* Behavior:
|
|
18
|
+
* - Enriches payloads with `appName` and `environment` from config when not provided.
|
|
19
|
+
* - Defaults `type` to "info" when `send` is called without an explicit type.
|
|
20
|
+
*
|
|
21
|
+
* @param config Configuration with `apiKey` and optional `appName`, `environment`.
|
|
22
|
+
* @returns Logger API with `send`, type helpers, `get`, and `stream`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createLogger(config: LoggerConfig): {
|
|
25
|
+
send: (payload: LogPayload) => Promise<void>;
|
|
26
|
+
info: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
27
|
+
error: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
28
|
+
metric: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
29
|
+
audit: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
30
|
+
warning: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
31
|
+
debug: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
32
|
+
success: (payload: Omit<LogPayload, "type">) => Promise<void>;
|
|
33
|
+
get: (filters?: Record<string, any>) => Promise<any>;
|
|
34
|
+
stream: (filters: Record<string, any>) => {
|
|
35
|
+
body: ReadableStream<Uint8Array> | null;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* oneminutelogs – createLogger
|
|
4
|
+
*
|
|
5
|
+
* Summary:
|
|
6
|
+
* Factory that creates a typed logger backed by OMLTransport. Provides:
|
|
7
|
+
* - `send` for generic logging
|
|
8
|
+
* - type helpers: `info`, `error`, `metric`, `audit`, `warning`
|
|
9
|
+
* - passthrough `get` and `stream` to query historical logs and subscribe to live logs
|
|
10
|
+
*
|
|
11
|
+
* Package: @oneminutelogs/express
|
|
12
|
+
* Module: core/createLogger
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createLogger = createLogger;
|
|
16
|
+
const transport_js_1 = require("../utils/transport.js");
|
|
17
|
+
/**
|
|
18
|
+
* Creates a logger bound to an OML transport.
|
|
19
|
+
*
|
|
20
|
+
* Behavior:
|
|
21
|
+
* - Enriches payloads with `appName` and `environment` from config when not provided.
|
|
22
|
+
* - Defaults `type` to "info" when `send` is called without an explicit type.
|
|
23
|
+
*
|
|
24
|
+
* @param config Configuration with `apiKey` and optional `appName`, `environment`.
|
|
25
|
+
* @returns Logger API with `send`, type helpers, `get`, and `stream`.
|
|
26
|
+
*/
|
|
27
|
+
function createLogger(config) {
|
|
28
|
+
const transport = new transport_js_1.OMLTransport(config);
|
|
29
|
+
/**
|
|
30
|
+
* Sends a log payload.
|
|
31
|
+
*
|
|
32
|
+
* Merges defaults:
|
|
33
|
+
* - `type`: defaults to "info"
|
|
34
|
+
* - `appName`: `payload.appName || config.appName || "default"`
|
|
35
|
+
* - `environment`: `payload.environment || config.environment || process.env.NODE_ENV || "development"`
|
|
36
|
+
*
|
|
37
|
+
* @param payload Log payload to send.
|
|
38
|
+
* @returns Promise that resolves when the payload is enqueued/flushed.
|
|
39
|
+
*/
|
|
40
|
+
const send = async (payload) => {
|
|
41
|
+
const { type = "info", message, importance, subsystem, operation, service, track, security, metrics, timestamps, appName, environment, } = payload;
|
|
42
|
+
const finalPayload = {
|
|
43
|
+
type,
|
|
44
|
+
message,
|
|
45
|
+
importance,
|
|
46
|
+
subsystem,
|
|
47
|
+
operation,
|
|
48
|
+
service,
|
|
49
|
+
track,
|
|
50
|
+
security,
|
|
51
|
+
metrics,
|
|
52
|
+
timestamps,
|
|
53
|
+
appName: appName || config.appName || "default",
|
|
54
|
+
environment: environment ||
|
|
55
|
+
config.environment ||
|
|
56
|
+
process.env.NODE_ENV ||
|
|
57
|
+
"development",
|
|
58
|
+
};
|
|
59
|
+
await transport.send(finalPayload);
|
|
60
|
+
};
|
|
61
|
+
// Helper factory to create type-specific methods dynamically
|
|
62
|
+
/**
|
|
63
|
+
* Factory for type-specific logging methods (e.g., `info`, `error`).
|
|
64
|
+
*
|
|
65
|
+
* @param type Log type to set on the outgoing payload.
|
|
66
|
+
* @returns Function that accepts a payload without `type` and sends it with the provided `type`.
|
|
67
|
+
*/
|
|
68
|
+
const createTypeMethod = (type) => (payload) => send({ ...payload, type });
|
|
69
|
+
/**
|
|
70
|
+
* Returned API:
|
|
71
|
+
* - `send(payload)`: send a generic log (defaults `type` to "info").
|
|
72
|
+
* - `info(payload)`, `error(payload)`, `metric(payload)`, `audit(payload)`, `warning(payload)`: type-specific helpers.
|
|
73
|
+
* - `get(filters?)`: fetch historical logs via transport.
|
|
74
|
+
* - `stream(filters?)`: open SSE stream via transport.
|
|
75
|
+
*/
|
|
76
|
+
return {
|
|
77
|
+
send,
|
|
78
|
+
info: createTypeMethod("info"),
|
|
79
|
+
error: createTypeMethod("error"),
|
|
80
|
+
metric: createTypeMethod("metric"),
|
|
81
|
+
audit: createTypeMethod("audit"),
|
|
82
|
+
warning: createTypeMethod("warning"),
|
|
83
|
+
debug: createTypeMethod("debug"),
|
|
84
|
+
success: createTypeMethod("success"),
|
|
85
|
+
get: (filters) => transport.get(filters),
|
|
86
|
+
stream: (filters) => transport.stream(filters),
|
|
87
|
+
};
|
|
88
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./types/index.js";
|
|
2
|
+
export * from "./OneMinuteLogsService.js";
|
|
3
|
+
export * from "./OneMinuteLogsModule.js";
|
|
4
|
+
export * from "./OneMinuteLogsInterceptor.js";
|
|
5
|
+
export { createLogger } from "./core/createLogger.js";
|
|
6
|
+
export { getLogs } from "./utils/getLogs.js";
|
|
7
|
+
export { getStream } from "./utils/getStream.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.getStream = exports.getLogs = exports.createLogger = void 0;
|
|
18
|
+
__exportStar(require("./types/index.js"), exports);
|
|
19
|
+
__exportStar(require("./OneMinuteLogsService.js"), exports);
|
|
20
|
+
__exportStar(require("./OneMinuteLogsModule.js"), exports);
|
|
21
|
+
__exportStar(require("./OneMinuteLogsInterceptor.js"), exports);
|
|
22
|
+
var createLogger_js_1 = require("./core/createLogger.js");
|
|
23
|
+
Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return createLogger_js_1.createLogger; } });
|
|
24
|
+
var getLogs_js_1 = require("./utils/getLogs.js");
|
|
25
|
+
Object.defineProperty(exports, "getLogs", { enumerable: true, get: function () { return getLogs_js_1.getLogs; } });
|
|
26
|
+
var getStream_js_1 = require("./utils/getStream.js");
|
|
27
|
+
Object.defineProperty(exports, "getStream", { enumerable: true, get: function () { return getStream_js_1.getStream; } });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LogTimestamps } from "./log.js";
|
|
2
|
+
import { LogMetrics } from "./metrics.js";
|
|
3
|
+
import { LogSecurity } from "./security.js";
|
|
4
|
+
import { LogTrack } from "./track.js";
|
|
5
|
+
export type LogLevel = "info" | "warn" | "error";
|
|
6
|
+
export interface LoggerConfig {
|
|
7
|
+
apiKey: string;
|
|
8
|
+
appName?: string;
|
|
9
|
+
environment?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface LogPayload {
|
|
12
|
+
type: LogType;
|
|
13
|
+
message: string;
|
|
14
|
+
importance?: Importance;
|
|
15
|
+
subsystem?: Subsystem;
|
|
16
|
+
operation?: string;
|
|
17
|
+
track?: LogTrack;
|
|
18
|
+
security?: LogSecurity;
|
|
19
|
+
metrics?: LogMetrics;
|
|
20
|
+
service?: string;
|
|
21
|
+
timestamps?: LogTimestamps;
|
|
22
|
+
ingested_at?: number;
|
|
23
|
+
appName?: string;
|
|
24
|
+
environment?: string;
|
|
25
|
+
}
|
|
26
|
+
export type LogType = "error" | "warning" | "info" | "audit" | "metric" | "debug" | "success";
|
|
27
|
+
export type Importance = "critical" | "high" | "medium" | "low";
|
|
28
|
+
export type Subsystem = "db" | "cache" | "queue" | "network";
|
|
29
|
+
export type UserRole = "super-admin" | "admin" | "user";
|
|
30
|
+
export type AuthStatus = "success" | "failed" | "expired";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type LogMetrics = Record<string, number | string | Record<string, any>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type LogSecurity = Record<string, any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type LogTrack = Record<string, any>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oneminutelogs – getLogs utility
|
|
3
|
+
*
|
|
4
|
+
* Summary:
|
|
5
|
+
* A utility function to fetch logs from the OML server.
|
|
6
|
+
* Unlike the Next.js SDK, this is not a hook but a plain async function.
|
|
7
|
+
*
|
|
8
|
+
* Package: @oneminutelogs/express
|
|
9
|
+
* Module: utils/getLogs
|
|
10
|
+
*/
|
|
11
|
+
import type { LoggerConfig } from "../types/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Result returned by `getLogs`.
|
|
14
|
+
* Wraps the server response.
|
|
15
|
+
*/
|
|
16
|
+
export type GetLogsResult<T = any> = T[] | {
|
|
17
|
+
logs: T[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Fetches logs from the OML server.
|
|
21
|
+
*
|
|
22
|
+
* @param config - Logger configuration (apiKey is required).
|
|
23
|
+
* @param filters - Optional filters (type, limit, search, etc.).
|
|
24
|
+
* @returns Promise resolving to the logs.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getLogs<T = any>(config: LoggerConfig, filters?: Record<string, any>): Promise<GetLogsResult<T>>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* oneminutelogs – getLogs utility
|
|
4
|
+
*
|
|
5
|
+
* Summary:
|
|
6
|
+
* A utility function to fetch logs from the OML server.
|
|
7
|
+
* Unlike the Next.js SDK, this is not a hook but a plain async function.
|
|
8
|
+
*
|
|
9
|
+
* Package: @oneminutelogs/express
|
|
10
|
+
* Module: utils/getLogs
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.getLogs = getLogs;
|
|
14
|
+
const transport_js_1 = require("./transport.js");
|
|
15
|
+
/**
|
|
16
|
+
* Fetches logs from the OML server.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Logger configuration (apiKey is required).
|
|
19
|
+
* @param filters - Optional filters (type, limit, search, etc.).
|
|
20
|
+
* @returns Promise resolving to the logs.
|
|
21
|
+
*/
|
|
22
|
+
async function getLogs(config, filters) {
|
|
23
|
+
const transport = new transport_js_1.OMLTransport(config);
|
|
24
|
+
return transport.get(filters);
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oneminutelogs – getStream utility
|
|
3
|
+
*
|
|
4
|
+
* Summary:
|
|
5
|
+
* A utility function to subscribe to the OML server SSE stream.
|
|
6
|
+
* Returns a ReadableStream of bytes.
|
|
7
|
+
*
|
|
8
|
+
* Package: @oneminutelogs/express
|
|
9
|
+
* Module: utils/getStream
|
|
10
|
+
*/
|
|
11
|
+
import type { LoggerConfig } from "../types/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Subscribes to the OML SSE stream.
|
|
14
|
+
*
|
|
15
|
+
* @param config - Logger configuration (apiKey is required).
|
|
16
|
+
* @param filters - Optional filters (type, limit, search, etc.).
|
|
17
|
+
* @returns Object containing the body stream.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getStream(config: LoggerConfig, filters: Record<string, any>): {
|
|
20
|
+
body: ReadableStream<Uint8Array> | null;
|
|
21
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* oneminutelogs – getStream utility
|
|
4
|
+
*
|
|
5
|
+
* Summary:
|
|
6
|
+
* A utility function to subscribe to the OML server SSE stream.
|
|
7
|
+
* Returns a ReadableStream of bytes.
|
|
8
|
+
*
|
|
9
|
+
* Package: @oneminutelogs/express
|
|
10
|
+
* Module: utils/getStream
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.getStream = getStream;
|
|
14
|
+
const transport_js_1 = require("./transport.js");
|
|
15
|
+
/**
|
|
16
|
+
* Subscribes to the OML SSE stream.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Logger configuration (apiKey is required).
|
|
19
|
+
* @param filters - Optional filters (type, limit, search, etc.).
|
|
20
|
+
* @returns Object containing the body stream.
|
|
21
|
+
*/
|
|
22
|
+
function getStream(config, filters) {
|
|
23
|
+
const transport = new transport_js_1.OMLTransport(config);
|
|
24
|
+
return transport.stream(filters);
|
|
25
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oneminutelogs – OMLTransport
|
|
3
|
+
*
|
|
4
|
+
* Summary:
|
|
5
|
+
* A thin transport client used by oneminutelogs SDK to:
|
|
6
|
+
* - batch and send logs to the OML server (`/send`)
|
|
7
|
+
* - query historical logs (`/logs`)
|
|
8
|
+
* - subscribe to live logs stream via SSE (`/logs/stream`)
|
|
9
|
+
*
|
|
10
|
+
* Package: @oneminutelogs/express
|
|
11
|
+
* Module: utils/transport
|
|
12
|
+
*/
|
|
13
|
+
import type { LoggerConfig, LogPayload } from "../types/index.js";
|
|
14
|
+
/**
|
|
15
|
+
* Transport for communicating with the OML server.
|
|
16
|
+
*
|
|
17
|
+
* Responsibilities:
|
|
18
|
+
* - Buffers logs client-side and flushes by interval or batch size.
|
|
19
|
+
* - Sends logs to `/send`.
|
|
20
|
+
* - Retrieves logs from `/logs` with optional filters.
|
|
21
|
+
* - Opens SSE stream from `/logs/stream`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class OMLTransport {
|
|
24
|
+
private config;
|
|
25
|
+
/** Base server URL (depends on env config). */
|
|
26
|
+
private baseUrl;
|
|
27
|
+
/** API key used for authentication (x-oml-api-key). */
|
|
28
|
+
private apiKey;
|
|
29
|
+
/** Optional app name used to tag requests (x-oml-app-name). */
|
|
30
|
+
private appName;
|
|
31
|
+
/** Optional environment used to tag requests (x-oml-env). */
|
|
32
|
+
private environment;
|
|
33
|
+
/** Default headers applied to outbound requests. */
|
|
34
|
+
private headers;
|
|
35
|
+
/** In-memory buffer of logs to batch-send. */
|
|
36
|
+
private buffer;
|
|
37
|
+
/** Scheduled timer for periodic flushes. */
|
|
38
|
+
private timer;
|
|
39
|
+
/** Flush interval in milliseconds for buffered logs. */
|
|
40
|
+
private flushInterval;
|
|
41
|
+
/** Indicates shutdown is in progress and new logs should be ignored. */
|
|
42
|
+
private shuttingDown;
|
|
43
|
+
/** Indicates whether a flush is currently in progress. */
|
|
44
|
+
private isFlushing;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new transport instance.
|
|
47
|
+
*
|
|
48
|
+
* @param config Logger configuration containing `apiKey`, and optionally `appName` and `environment`.
|
|
49
|
+
*/
|
|
50
|
+
constructor(config: LoggerConfig);
|
|
51
|
+
/** Queues a single log payload for sending. */
|
|
52
|
+
send(payload: LogPayload): Promise<void>;
|
|
53
|
+
/** Flushes the in-memory buffer to the server as a single batch. */
|
|
54
|
+
private flush;
|
|
55
|
+
/** Registers process-level handlers (SIGINT, SIGTERM, beforeExit) */
|
|
56
|
+
private setupGracefulShutdown;
|
|
57
|
+
/** Retrieves historical logs from the server. */
|
|
58
|
+
get(filters?: Record<string, any>): Promise<any>;
|
|
59
|
+
/** Opens a Server-Sent Events (SSE) stream of live logs. */
|
|
60
|
+
stream(filters: Record<string, string>): {
|
|
61
|
+
body: ReadableStream<Uint8Array> | null;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* oneminutelogs – OMLTransport
|
|
4
|
+
*
|
|
5
|
+
* Summary:
|
|
6
|
+
* A thin transport client used by oneminutelogs SDK to:
|
|
7
|
+
* - batch and send logs to the OML server (`/send`)
|
|
8
|
+
* - query historical logs (`/logs`)
|
|
9
|
+
* - subscribe to live logs stream via SSE (`/logs/stream`)
|
|
10
|
+
*
|
|
11
|
+
* Package: @oneminutelogs/express
|
|
12
|
+
* Module: utils/transport
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.OMLTransport = void 0;
|
|
16
|
+
const index_js_1 = require("../configs/index.js");
|
|
17
|
+
/**
|
|
18
|
+
* Transport for communicating with the OML server.
|
|
19
|
+
*
|
|
20
|
+
* Responsibilities:
|
|
21
|
+
* - Buffers logs client-side and flushes by interval or batch size.
|
|
22
|
+
* - Sends logs to `/send`.
|
|
23
|
+
* - Retrieves logs from `/logs` with optional filters.
|
|
24
|
+
* - Opens SSE stream from `/logs/stream`.
|
|
25
|
+
*/
|
|
26
|
+
class OMLTransport {
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new transport instance.
|
|
29
|
+
*
|
|
30
|
+
* @param config Logger configuration containing `apiKey`, and optionally `appName` and `environment`.
|
|
31
|
+
*/
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.config = config;
|
|
34
|
+
/** In-memory buffer of logs to batch-send. */
|
|
35
|
+
this.buffer = [];
|
|
36
|
+
/** Scheduled timer for periodic flushes. */
|
|
37
|
+
this.timer = null;
|
|
38
|
+
/** Flush interval in milliseconds for buffered logs. */
|
|
39
|
+
this.flushInterval = 2000;
|
|
40
|
+
/** Indicates shutdown is in progress and new logs should be ignored. */
|
|
41
|
+
this.shuttingDown = false;
|
|
42
|
+
/** Indicates whether a flush is currently in progress. */
|
|
43
|
+
this.isFlushing = false;
|
|
44
|
+
const envConfig = (0, index_js_1.getEnvConfig)();
|
|
45
|
+
this.baseUrl = envConfig.baseUrl;
|
|
46
|
+
this.apiKey = config.apiKey;
|
|
47
|
+
this.appName = config.appName;
|
|
48
|
+
this.environment = config.environment;
|
|
49
|
+
this.headers = {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
"x-oml-api-key": config.apiKey,
|
|
52
|
+
...(config.appName ? { "x-oml-app-name": config.appName } : {}),
|
|
53
|
+
...(config.environment ? { "x-oml-env": config.environment } : {}),
|
|
54
|
+
};
|
|
55
|
+
this.setupGracefulShutdown();
|
|
56
|
+
}
|
|
57
|
+
/** Queues a single log payload for sending. */
|
|
58
|
+
async send(payload) {
|
|
59
|
+
if (this.shuttingDown)
|
|
60
|
+
return; // ignore new logs during shutdown
|
|
61
|
+
this.buffer.push({
|
|
62
|
+
...payload,
|
|
63
|
+
ingested_at: Date.now(),
|
|
64
|
+
});
|
|
65
|
+
// Rely on the 2s periodic flush
|
|
66
|
+
if (!this.timer) {
|
|
67
|
+
this.timer = setTimeout(() => this.flush(), this.flushInterval);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Flushes the in-memory buffer to the server as a single batch. */
|
|
71
|
+
async flush() {
|
|
72
|
+
// Prevent multiple flushes from running simultaneously.
|
|
73
|
+
if (this.isFlushing)
|
|
74
|
+
return;
|
|
75
|
+
this.isFlushing = true;
|
|
76
|
+
if (this.timer) {
|
|
77
|
+
clearTimeout(this.timer);
|
|
78
|
+
this.timer = null;
|
|
79
|
+
}
|
|
80
|
+
const batch = this.buffer.splice(0, this.buffer.length);
|
|
81
|
+
if (batch.length === 0) {
|
|
82
|
+
this.isFlushing = false;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
await fetch(`${this.baseUrl}/send`, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers: this.headers,
|
|
89
|
+
body: JSON.stringify({ logs: batch }),
|
|
90
|
+
// @ts-ignore: keepalive might not be in all fetch types, but supported in modern node
|
|
91
|
+
keepalive: true,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error("OMLTransport flush failed:", err);
|
|
96
|
+
}
|
|
97
|
+
this.isFlushing = false;
|
|
98
|
+
}
|
|
99
|
+
/** Registers process-level handlers (SIGINT, SIGTERM, beforeExit) */
|
|
100
|
+
setupGracefulShutdown() {
|
|
101
|
+
const shutdownHandler = async (signal) => {
|
|
102
|
+
if (this.shuttingDown)
|
|
103
|
+
return;
|
|
104
|
+
this.shuttingDown = true;
|
|
105
|
+
try {
|
|
106
|
+
await this.flush();
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.error("[OMLTransport] Flush during shutdown failed:", err);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
process.on("beforeExit", () => shutdownHandler("beforeExit"));
|
|
116
|
+
process.on("SIGINT", () => shutdownHandler("SIGINT"));
|
|
117
|
+
process.on("SIGTERM", () => shutdownHandler("SIGTERM"));
|
|
118
|
+
}
|
|
119
|
+
/** Retrieves historical logs from the server. */
|
|
120
|
+
async get(filters) {
|
|
121
|
+
const headers = {
|
|
122
|
+
"x-oml-api-key": this.apiKey,
|
|
123
|
+
...(this.appName ? { "x-oml-app-name": this.appName } : {}),
|
|
124
|
+
...(this.environment ? { "x-oml-env": this.environment } : {}),
|
|
125
|
+
};
|
|
126
|
+
const qs = filters && Object.keys(filters).length > 0
|
|
127
|
+
? `?${new URLSearchParams(filters).toString()}`
|
|
128
|
+
: "";
|
|
129
|
+
const res = await fetch(`${this.baseUrl}/logs${qs}`, { headers });
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
const text = await res.text();
|
|
132
|
+
throw new Error(`OML get failed (${res.status}): ${text.slice(0, 200)}`);
|
|
133
|
+
}
|
|
134
|
+
return res.json();
|
|
135
|
+
}
|
|
136
|
+
/** Opens a Server-Sent Events (SSE) stream of live logs. */
|
|
137
|
+
stream(filters) {
|
|
138
|
+
const qs = new URLSearchParams(filters).toString();
|
|
139
|
+
const url = `${this.baseUrl}/logs/stream?${qs}`;
|
|
140
|
+
const headers = {
|
|
141
|
+
"x-oml-api-key": this.apiKey,
|
|
142
|
+
...(this.appName ? { "x-oml-app-name": this.appName } : {}),
|
|
143
|
+
...(this.environment ? { "x-oml-env": this.environment } : {}),
|
|
144
|
+
};
|
|
145
|
+
const abortController = new AbortController();
|
|
146
|
+
// In node-fetch or native fetch, response.body is a stream.
|
|
147
|
+
// We return a wrapped object to match similar API pattern or just return the fetch promise.
|
|
148
|
+
// However, to keep it sync-like wrapper (returning stream object immediately), we can't do await fetch.
|
|
149
|
+
// The original code was async inside ReadableStream start.
|
|
150
|
+
// For Node.js consumption, we probably want a simpler async method or return the promise of the stream.
|
|
151
|
+
// But adhering to the interface:
|
|
152
|
+
const readable = new ReadableStream({
|
|
153
|
+
start: async (controller) => {
|
|
154
|
+
try {
|
|
155
|
+
const res = await fetch(url, {
|
|
156
|
+
headers,
|
|
157
|
+
signal: abortController.signal,
|
|
158
|
+
});
|
|
159
|
+
if (!res.body) {
|
|
160
|
+
controller.error(new Error("Upstream stream unavailable"));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// @ts-ignore
|
|
164
|
+
const reader = res.body.getReader();
|
|
165
|
+
while (true) {
|
|
166
|
+
const { done, value } = await reader.read();
|
|
167
|
+
if (done)
|
|
168
|
+
break;
|
|
169
|
+
if (value)
|
|
170
|
+
controller.enqueue(value);
|
|
171
|
+
}
|
|
172
|
+
controller.close();
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
controller.error(err);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
cancel() {
|
|
179
|
+
abortController.abort();
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
return { body: readable };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.OMLTransport = OMLTransport;
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oneminutelogs/nestjs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "NestJS SDK for OneMinuteLogs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/One-Minute-Stack/oneminutelogs-nestjs.git"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"logging",
|
|
27
|
+
"nestjs",
|
|
28
|
+
"oneminutelogs",
|
|
29
|
+
"logger",
|
|
30
|
+
"monitoring",
|
|
31
|
+
"observability"
|
|
32
|
+
],
|
|
33
|
+
"author": "OneMinute Stack",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/One-Minute-Stack/oneminutelogs-nestjs/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://oneminutelogs.com/docs/nestjs",
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
|
41
|
+
"@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
|
42
|
+
"rxjs": "^7.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@nestjs/common": "^10.0.0",
|
|
46
|
+
"@nestjs/core": "^10.0.0",
|
|
47
|
+
"@types/node": "^20.0.0",
|
|
48
|
+
"reflect-metadata": "^0.1.13",
|
|
49
|
+
"rxjs": "^7.8.1",
|
|
50
|
+
"typescript": "^5.0.0"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
}
|
|
55
|
+
}
|