@hemia/trace-manager 0.0.1 → 0.0.2
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 +1 -2
- package/dist/hemia-trace-manager.esm.js +1 -1
- package/dist/hemia-trace-manager.js +1 -1
- package/dist/types/decorator/Traceable.d.ts +6 -4
- package/dist/types/index.d.ts +3 -5
- package/dist/types/log/Logger.d.ts +15 -0
- package/dist/types/types/traceOptions.d.ts +5 -18
- package/package.json +3 -3
- package/dist/types/TraceManager.d.ts +0 -50
- package/dist/types/types/traceModel.d.ts +0 -63
- package/dist/types/types/traceSchema.d.ts +0 -11
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{asyncContext as t}from"@hemia/app-context";
|
|
1
|
+
import{asyncContext as t}from"@hemia/app-context";var e;!function(t){t.TRACE="x-trace-id",t.CORRELATION="x-correlation-id"}(e||(e={}));const n={DEBUG:5,INFO:9,WARN:13,ERROR:17,FATAL:21};const r=new class{constructor(t){this.defaultServiceName=t}log(e,r,o){const s=t.getStore();if(!s)return console.warn("[Logger] No active context. Log not traced."),void console.log(`[${e}] ${r}`,o);const a={Timestamp:(new Date).toISOString(),TraceId:s.traceId,SpanId:s.spanId,TraceFlags:1,SeverityText:e,SeverityNumber:n[e],ServiceName:s.serviceName,Body:r,LogAttributes:this.stringifyAttributes(o||{}),ResourceAttributes:s.traceContext.resourceAttributes};s.traceContext.logs.push(a),"production"!==process.env.NODE_ENV&&console.log(`[${e}] [TraceId:${s.traceId.substring(0,8)}...] ${r}`,o||"")}stringifyAttributes(t){const e={};for(const[n,r]of Object.entries(t))if(null==r)e[n]="";else if("string"==typeof r)e[n]=r;else try{e[n]=JSON.stringify(r)}catch{e[n]=String(r)}return e}debug(t,e){this.log("DEBUG",t,e)}info(t,e){this.log("INFO",t,e)}warn(t,e){this.log("WARN",t,e)}error(t,e){this.log("ERROR",t,e)}fatal(t,e){this.log("FATAL",t,e)}};function o(t){try{const e=JSON.stringify(t,function(){const t=new WeakSet;return(e,n)=>{if(null===n)return null;if("object"==typeof n){if(t.has(n))return"[Circular]";t.add(n)}return"function"==typeof n?n.toString():n}}());return JSON.parse(e)}catch(e){return String(t)}}const s=["content-type","host","x-no-cookies","x-api-key","Authorization","origin"];function a(t){return t.map(t=>{if(function(t){return null!=t&&"object"==typeof t&&"string"==typeof t.method&&"string"==typeof t.url&&"object"==typeof t.headers}(t)){const e=s.reduce((e,n)=>{const r=n.toLowerCase();return t.headers[r]&&(e[r]=t.headers[r]),e},{});return{method:t.method,url:t.url,params:t.params,query:t.query,body:t.body,headers:e}}return function(t){return null!=t&&"object"==typeof t&&"number"==typeof t.statusCode&&"function"==typeof t.setHeader&&"function"==typeof t.end}(t)?"[ExpressResponseObject]":"function"==typeof t?"[Function next]":t})}for(var i,c=[],u=0;u<256;++u)c.push((u+256).toString(16).slice(1));var p=new Uint8Array(16);function d(){if(!i&&!(i="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return i(p)}var f={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function g(t,e,n){if(f.randomUUID&&!t)return f.randomUUID();var r=(t=t||{}).random||(t.rng||d)();return r[6]=15&r[6]|64,r[8]=63&r[8]|128,function(t,e=0){return(c[t[e+0]]+c[t[e+1]]+c[t[e+2]]+c[t[e+3]]+"-"+c[t[e+4]]+c[t[e+5]]+"-"+c[t[e+6]]+c[t[e+7]]+"-"+c[t[e+8]]+c[t[e+9]]+"-"+c[t[e+10]]+c[t[e+11]]+c[t[e+12]]+c[t[e+13]]+c[t[e+14]]+c[t[e+15]]).toLowerCase()}(r)}function l(e){return function(n,r,s){const i=s?.value;if("function"!=typeof i)throw new Error("@Trace can only be applied to methods");s.value=async function(...s){const c=t.getStore();if(!c)return console.warn("[Trace] No active context. Skipping trace."),await i.apply(this,s);const u=g(),p=this?.constructor?.name||n.name||"UnknownClass",d=e?.name||`${p}.${r}`,f=process.hrtime.bigint(),l=(new Date).toISOString(),m=c.spanId,y={Timestamp:l,TraceId:c.traceId,SpanId:u,ParentSpanId:m,TraceState:"",ServiceName:c.serviceName,SpanName:d,SpanKind:e?.kind||"SPAN_KIND_INTERNAL",DurationUInt64:BigInt(0),StatusCode:"STATUS_CODE_UNSET",StatusMessage:"",SpanAttributes:{"code.function":r,"code.namespace":p,...e?.attributes},ResourceAttributes:c.traceContext.resourceAttributes,EventsNested:[],LinksNested:[]},S=c.spanId;c.spanId=u;try{const t=a(s);y.SpanAttributes["app.method.args"]=o(t),y.SpanAttributes["app.method.args.count"]=s.length.toString();const e=await i.apply(this,s),n=o(a(Array.isArray(e)?e:[e]));return y.SpanAttributes["app.method.result"]=n.substring(0,2e3),y.StatusCode="STATUS_CODE_OK",e}catch(t){const e={Timestamp:(new Date).toISOString(),Name:"exception",Attributes:{"exception.type":t.constructor?.name||"Error","exception.message":t.message||"Unknown error","exception.stacktrace":(t.stack||"").substring(0,5e3)}};throw y.EventsNested.push(e),y.StatusCode="STATUS_CODE_ERROR",y.StatusMessage=t.message||"Unhandled exception",t}finally{const t=process.hrtime.bigint();y.DurationUInt64=t-f,c.traceContext.spans.push(y),c.spanId=S}}}}export{l as Trace,e as TraceHeader,r as logger};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t,e=require("@hemia/app-context"),
|
|
1
|
+
"use strict";var t,e=require("@hemia/app-context");exports.TraceHeader=void 0,(t=exports.TraceHeader||(exports.TraceHeader={})).TRACE="x-trace-id",t.CORRELATION="x-correlation-id";const r={DEBUG:5,INFO:9,WARN:13,ERROR:17,FATAL:21};const n=new class{constructor(t){this.defaultServiceName=t}log(t,n,o){const s=e.asyncContext.getStore();if(!s)return console.warn("[Logger] No active context. Log not traced."),void console.log(`[${t}] ${n}`,o);const a={Timestamp:(new Date).toISOString(),TraceId:s.traceId,SpanId:s.spanId,TraceFlags:1,SeverityText:t,SeverityNumber:r[t],ServiceName:s.serviceName,Body:n,LogAttributes:this.stringifyAttributes(o||{}),ResourceAttributes:s.traceContext.resourceAttributes};s.traceContext.logs.push(a),"production"!==process.env.NODE_ENV&&console.log(`[${t}] [TraceId:${s.traceId.substring(0,8)}...] ${n}`,o||"")}stringifyAttributes(t){const e={};for(const[r,n]of Object.entries(t))if(null==n)e[r]="";else if("string"==typeof n)e[r]=n;else try{e[r]=JSON.stringify(n)}catch{e[r]=String(n)}return e}debug(t,e){this.log("DEBUG",t,e)}info(t,e){this.log("INFO",t,e)}warn(t,e){this.log("WARN",t,e)}error(t,e){this.log("ERROR",t,e)}fatal(t,e){this.log("FATAL",t,e)}};function o(t){try{const e=JSON.stringify(t,function(){const t=new WeakSet;return(e,r)=>{if(null===r)return null;if("object"==typeof r){if(t.has(r))return"[Circular]";t.add(r)}return"function"==typeof r?r.toString():r}}());return JSON.parse(e)}catch(e){return String(t)}}const s=["content-type","host","x-no-cookies","x-api-key","Authorization","origin"];function a(t){return t.map(t=>{if(function(t){return null!=t&&"object"==typeof t&&"string"==typeof t.method&&"string"==typeof t.url&&"object"==typeof t.headers}(t)){const e=s.reduce((e,r)=>{const n=r.toLowerCase();return t.headers[n]&&(e[n]=t.headers[n]),e},{});return{method:t.method,url:t.url,params:t.params,query:t.query,body:t.body,headers:e}}return function(t){return null!=t&&"object"==typeof t&&"number"==typeof t.statusCode&&"function"==typeof t.setHeader&&"function"==typeof t.end}(t)?"[ExpressResponseObject]":"function"==typeof t?"[Function next]":t})}for(var i,c=[],u=0;u<256;++u)c.push((u+256).toString(16).slice(1));var p=new Uint8Array(16);function d(){if(!i&&!(i="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return i(p)}var f={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function g(t,e,r){if(f.randomUUID&&!t)return f.randomUUID();var n=(t=t||{}).random||(t.rng||d)();return n[6]=15&n[6]|64,n[8]=63&n[8]|128,function(t,e=0){return(c[t[e+0]]+c[t[e+1]]+c[t[e+2]]+c[t[e+3]]+"-"+c[t[e+4]]+c[t[e+5]]+"-"+c[t[e+6]]+c[t[e+7]]+"-"+c[t[e+8]]+c[t[e+9]]+"-"+c[t[e+10]]+c[t[e+11]]+c[t[e+12]]+c[t[e+13]]+c[t[e+14]]+c[t[e+15]]).toLowerCase()}(n)}exports.Trace=function(t){return function(r,n,s){const i=s?.value;if("function"!=typeof i)throw new Error("@Trace can only be applied to methods");s.value=async function(...s){const c=e.asyncContext.getStore();if(!c)return console.warn("[Trace] No active context. Skipping trace."),await i.apply(this,s);const u=g(),p=this?.constructor?.name||r.name||"UnknownClass",d=t?.name||`${p}.${n}`,f=process.hrtime.bigint(),l=(new Date).toISOString(),y=c.spanId,m={Timestamp:l,TraceId:c.traceId,SpanId:u,ParentSpanId:y,TraceState:"",ServiceName:c.serviceName,SpanName:d,SpanKind:t?.kind||"SPAN_KIND_INTERNAL",DurationUInt64:BigInt(0),StatusCode:"STATUS_CODE_UNSET",StatusMessage:"",SpanAttributes:{"code.function":n,"code.namespace":p,...t?.attributes},ResourceAttributes:c.traceContext.resourceAttributes,EventsNested:[],LinksNested:[]},S=c.spanId;c.spanId=u;try{const t=a(s);m.SpanAttributes["app.method.args"]=o(t),m.SpanAttributes["app.method.args.count"]=s.length.toString();const e=await i.apply(this,s),r=o(a(Array.isArray(e)?e:[e]));return m.SpanAttributes["app.method.result"]=r.substring(0,2e3),m.StatusCode="STATUS_CODE_OK",e}catch(t){const e={Timestamp:(new Date).toISOString(),Name:"exception",Attributes:{"exception.type":t.constructor?.name||"Error","exception.message":t.message||"Unknown error","exception.stacktrace":(t.stack||"").substring(0,5e3)}};throw m.EventsNested.push(e),m.StatusCode="STATUS_CODE_ERROR",m.StatusMessage=t.message||"Unhandled exception",t}finally{const t=process.hrtime.bigint();m.DurationUInt64=t-f,c.traceContext.spans.push(m),c.spanId=S}}}},exports.logger=n;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { TraceOptions } from "../types/traceOptions";
|
|
2
|
+
/**
|
|
3
|
+
* Decorador que captura método como Span en formato OpenTelemetry/ClickHouse
|
|
4
|
+
* Usa AsyncLocalStorage para propagar contexto automáticamente
|
|
5
|
+
*/
|
|
6
|
+
export declare function Trace(options?: TraceOptions): <T extends (...args: any[]) => any>(target: any, key: string, descriptor: PropertyDescriptor) => void;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { TraceHeader } from "./types/traceHeadersNames";
|
|
2
2
|
export { TraceContext } from "./types/traceContext";
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export { Trace, ITrace } from "./types/traceModel";
|
|
7
|
-
export { TraceSchema } from "./types/traceSchema";
|
|
3
|
+
export { TraceOptions } from "./types/traceOptions";
|
|
4
|
+
export { logger } from "./log/Logger";
|
|
5
|
+
export { Trace } from "./decorator/Traceable";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class Logger {
|
|
2
|
+
private defaultServiceName?;
|
|
3
|
+
constructor(defaultServiceName?: string | undefined);
|
|
4
|
+
/**
|
|
5
|
+
* Logs que se correlacionan automáticamente con el TraceId activo
|
|
6
|
+
*/
|
|
7
|
+
private log;
|
|
8
|
+
private stringifyAttributes;
|
|
9
|
+
debug(message: string, attributes?: Record<string, any>): void;
|
|
10
|
+
info(message: string, attributes?: Record<string, any>): void;
|
|
11
|
+
warn(message: string, attributes?: Record<string, any>): void;
|
|
12
|
+
error(message: string, attributes?: Record<string, any>): void;
|
|
13
|
+
fatal(message: string, attributes?: Record<string, any>): void;
|
|
14
|
+
}
|
|
15
|
+
export declare const logger: Logger;
|
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* @property {string} st - Estado inicial o mensaje que indica el inicio del trazo.
|
|
7
|
-
* @property {string} [errSt] - Estado o mensaje que describe el error (opcional).
|
|
8
|
-
* @property {string} [errCode] - Código que identifica el tipo de error (opcional).
|
|
9
|
-
*/
|
|
10
|
-
export interface ITraceOptions {
|
|
11
|
-
ck?: string;
|
|
12
|
-
fn?: string;
|
|
13
|
-
st?: string;
|
|
14
|
-
errSt?: string;
|
|
15
|
-
errCode?: string;
|
|
16
|
-
description?: string;
|
|
17
|
-
tags?: string[];
|
|
18
|
-
source?: 'api' | 'web' | 'mobile' | 'cron' | 'system' | string;
|
|
1
|
+
import { TraceSpan } from "@hemia/app-context";
|
|
2
|
+
export interface TraceOptions {
|
|
3
|
+
name?: string;
|
|
4
|
+
kind?: TraceSpan['SpanKind'];
|
|
5
|
+
attributes?: Record<string, string>;
|
|
19
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hemia/trace-manager",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Gestor de trazas para registrar logs, errores y evento",
|
|
5
5
|
"main": "dist/hemia-trace-manager.js",
|
|
6
6
|
"module": "dist/hemia-trace-manager.esm.js",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"test": "jest --passWithNoTests --detectOpenHandles"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@hemia/app-context": "^0.0.
|
|
17
|
-
"@hemia/db-manager": "^0.0.
|
|
16
|
+
"@hemia/app-context": "^0.0.3",
|
|
17
|
+
"@hemia/db-manager": "^0.0.6",
|
|
18
18
|
"@rollup/plugin-commonjs": "^26.0.1",
|
|
19
19
|
"@rollup/plugin-json": "^6.1.0",
|
|
20
20
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { AggregateOptions, ClientSession, NoSQLOptions, NoSQLRepository, PipelineStage, FilterQuery, Document } from "@hemia/db-manager";
|
|
2
|
-
export declare class TraceManager<T extends Document> {
|
|
3
|
-
private repository;
|
|
4
|
-
constructor(service: NoSQLRepository<T>);
|
|
5
|
-
/**
|
|
6
|
-
* Servicio que permite guardar LOGS
|
|
7
|
-
* @param level - Nivel del Log
|
|
8
|
-
* @param message - Mensaje
|
|
9
|
-
* @param traceId - Trace ID
|
|
10
|
-
* @param trace - Traza
|
|
11
|
-
* @param additionalData - Datos adicionales
|
|
12
|
-
* @returns Documento guardado
|
|
13
|
-
*/
|
|
14
|
-
save(traceId: string, additionalData?: Partial<T>): Promise<T | null>;
|
|
15
|
-
/**
|
|
16
|
-
* Servicio que permite buscar documentos en la colección
|
|
17
|
-
* @param filter Filtros que se aplican en la colección
|
|
18
|
-
* @returns Lista de documentos de la colección
|
|
19
|
-
*/
|
|
20
|
-
find(filter: FilterQuery<T>, options?: NoSQLOptions): Promise<T[]>;
|
|
21
|
-
/**
|
|
22
|
-
* Servicio que permite buscar un documento en la colleción
|
|
23
|
-
* @param filter - Filtros de la colección
|
|
24
|
-
* @returns Documentos de la colección
|
|
25
|
-
*/
|
|
26
|
-
findOne(filter: FilterQuery<T>): Promise<T | null>;
|
|
27
|
-
/**
|
|
28
|
-
* Servicio que permite obtener un documento por ID
|
|
29
|
-
* @param id - Identificador del documento
|
|
30
|
-
* @returns Documento
|
|
31
|
-
*/
|
|
32
|
-
getById(id: string): Promise<T | null>;
|
|
33
|
-
/**
|
|
34
|
-
* Serivicio para actualizar documentos en la base de datos
|
|
35
|
-
* @param filter - criterio de actualización
|
|
36
|
-
* @param updateData - Datos del documento a actualizar
|
|
37
|
-
* @returns Documento actualizado
|
|
38
|
-
*/
|
|
39
|
-
update(filter: FilterQuery<T>, updateData: Partial<T>, session?: ClientSession): Promise<T | null>;
|
|
40
|
-
/**
|
|
41
|
-
* Servicio para eliminar un documento de la base de datos
|
|
42
|
-
* @param id - Identificador del documento
|
|
43
|
-
* @returns Documento Eliminado
|
|
44
|
-
*/
|
|
45
|
-
delete(filter: FilterQuery<T>, session?: ClientSession): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Ejecuta una consulta de agregación con un pipeline personalizado.
|
|
48
|
-
*/
|
|
49
|
-
aggregate(pipeline: PipelineStage[], options?: AggregateOptions): Promise<any[]>;
|
|
50
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Document } from "mongoose";
|
|
2
|
-
export interface ITrace extends Document {
|
|
3
|
-
traceId: string;
|
|
4
|
-
projectId: string;
|
|
5
|
-
meta?: TraceMetadata;
|
|
6
|
-
trace: Trace[];
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Node de las trazas
|
|
10
|
-
*/
|
|
11
|
-
export interface Trace {
|
|
12
|
-
description: string;
|
|
13
|
-
traceId: string;
|
|
14
|
-
spanId: string;
|
|
15
|
-
parentSpanId: string;
|
|
16
|
-
projectId: string;
|
|
17
|
-
parentId?: number;
|
|
18
|
-
checkpoint: string;
|
|
19
|
-
function: string;
|
|
20
|
-
status: boolean;
|
|
21
|
-
type: "input" | "output";
|
|
22
|
-
startTime: number;
|
|
23
|
-
endTime?: number;
|
|
24
|
-
duration?: number;
|
|
25
|
-
inputData?: any;
|
|
26
|
-
outputData?: any;
|
|
27
|
-
additionalData?: any;
|
|
28
|
-
tags?: string[];
|
|
29
|
-
error?: {
|
|
30
|
-
message: string;
|
|
31
|
-
code?: string;
|
|
32
|
-
stack?: string;
|
|
33
|
-
};
|
|
34
|
-
source?: 'api' | 'web' | 'mobile' | 'cron' | 'system' | string;
|
|
35
|
-
}
|
|
36
|
-
export interface TraceMetadata {
|
|
37
|
-
userAgent: string | null;
|
|
38
|
-
environment: string | null;
|
|
39
|
-
platform: string | null;
|
|
40
|
-
ip: string | null;
|
|
41
|
-
user: {
|
|
42
|
-
id: string;
|
|
43
|
-
email: string;
|
|
44
|
-
} | null;
|
|
45
|
-
event: string;
|
|
46
|
-
url: string;
|
|
47
|
-
path: string;
|
|
48
|
-
route: string | null;
|
|
49
|
-
tags: string[];
|
|
50
|
-
browser: {
|
|
51
|
-
name: string | null;
|
|
52
|
-
version: string | null;
|
|
53
|
-
};
|
|
54
|
-
os: {
|
|
55
|
-
name: string | null;
|
|
56
|
-
version: string | null;
|
|
57
|
-
};
|
|
58
|
-
device: {
|
|
59
|
-
model: string | null;
|
|
60
|
-
type: string | null;
|
|
61
|
-
vendor: string | null;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Schema } from "@hemia/db-manager";
|
|
2
|
-
import { ITrace } from "./traceModel";
|
|
3
|
-
export declare const TraceSchema: Schema<ITrace, import("mongoose").Model<ITrace, any, any, any, import("mongoose").Document<unknown, any, ITrace, any, {}> & ITrace & Required<{
|
|
4
|
-
_id: unknown;
|
|
5
|
-
}> & {
|
|
6
|
-
__v: number;
|
|
7
|
-
}, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, ITrace, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<ITrace>, {}, import("mongoose").ResolveSchemaOptions<import("mongoose").DefaultSchemaOptions>> & import("mongoose").FlatRecord<ITrace> & Required<{
|
|
8
|
-
_id: unknown;
|
|
9
|
-
}> & {
|
|
10
|
-
__v: number;
|
|
11
|
-
}>;
|