@logtail/node
Version:
Better Stack Node.js logger (formerly Logtail)
106 lines • 4.37 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Node = void 0;
const msgpack_1 = require("@msgpack/msgpack");
const node_http_1 = __importDefault(require("node:http"));
const node_https_1 = __importDefault(require("node:https"));
const node_zlib_1 = __importDefault(require("node:zlib"));
const core_1 = require("@logtail/core");
const context_1 = require("./context");
class Node extends core_1.Base {
constructor(sourceToken, options) {
options = Object.assign({ timeout: 30000 }, options);
super(sourceToken, options);
const agent = this.createAgent();
// Sync function
const sync = async (logs) => {
const nodeOptions = this._options;
const request = this.getHttpModule().request(nodeOptions.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/msgpack",
"Content-Encoding": "gzip",
Authorization: `Bearer ${this._sourceToken}`,
"User-Agent": "logtail-js(node)",
},
agent,
timeout: nodeOptions.timeout > 0 ? nodeOptions.timeout : undefined,
});
const response = await new Promise((resolve, reject) => {
// Setup timeout handler if timeout is configured
if (nodeOptions.timeout > 0) {
request.on("timeout", () => {
request.destroy();
reject(new Error(`Request timeout after ${nodeOptions.timeout}ms`));
});
}
request.on("response", resolve);
request.on("error", reject);
// Compress the logs using gzip
node_zlib_1.default.gzip(this.encodeAsMsgpack(logs), (err, compressedData) => {
if (err) {
reject(err);
return;
}
request.write(compressedData);
request.end();
});
});
if (response.statusCode && response.statusCode >= 200 && response.statusCode < 300) {
return logs;
}
throw new Error(response.statusMessage);
};
// Set the throttled sync function
this.setSync(sync);
}
/**
* Override `Base` log to enable Node.js streaming
*
* @param message: string - Log message
* @param level (LogLevel) - Level to log at (debug|info|warn|error)
* @param context: (Context) - Log context for passing structured data
* @param stackContextHint: (StackContextHint|null) - Info about which methods to consider as origin in context.runtime
* @returns Promise<ILogtailLog> after syncing
*/
async log(message, level, context = {}, stackContextHint) {
// Process/sync the log, per `Base` logic
context = Object.assign(Object.assign({}, (0, context_1.getStackContext)(this, stackContextHint)), context);
const processedLog = await super.log(message, level, context);
// Push the processed log to the stream, for piping
if (this._writeStream) {
this._writeStream.write(JSON.stringify(processedLog) + "\n");
}
// Return the transformed log
return processedLog;
}
/**
* Pipe JSON stringified `ILogtailLog` to a stream after syncing
*
* @param stream - Writable|Duplex stream
*/
pipe(stream) {
this._writeStream = stream;
return stream;
}
encodeAsMsgpack(logs) {
const encoded = (0, msgpack_1.encode)(logs);
const buffer = Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);
return buffer;
}
createAgent() {
const nodeOptions = this._options;
const family = nodeOptions.useIPv6 ? 6 : 4;
return new (this.getHttpModule().Agent)({
family,
});
}
getHttpModule() {
return this._options.endpoint.startsWith("https") ? node_https_1.default : node_http_1.default;
}
}
exports.Node = Node;
//# sourceMappingURL=node.js.map