@kumologica/kumologica-contrib-splunk
Version:
Node that integrates with Splunk.
130 lines (113 loc) • 4.47 kB
JavaScript
module.exports = function (App) {
const { KLNode } = require('@kumologica/devkit');
class SplunkError extends Error {
constructor(error) {
super(error);
this.originalError = error;
}
}
class SplunkConnectionError extends SplunkError {
constructor(error) {
super(error);
this.name = 'SplunkConnectionError';
this.message = 'Error connecting to the splunk server with provided connection params.';
this.statusCode = 408;
}
}
class SplunkInvalidTokenError extends SplunkError {
constructor(error) {
super(error);
this.name = 'SplunkInvalidTokenError';
this.message = 'Token supplied for connecting to Splunk is invalid.';
this.statusCode = 400;
}
}
class SplunkDataWriteError extends SplunkError {
constructor(error) {
super(error);
this.name = 'SplunkDataWriteError';
this.message = 'Error occurred while trying to write data to Splunk.'
this.statusCode = 400;
}
}
class KumologicaSplunkNode extends KLNode {
constructor(props) {
super(App, props);
this.nodeConfig = props;
this.typeValues = null;
this.splunkLogger = null;
this.messageToProcess = null;
this.consoleOutput = props.consoleOutput || false;
}
handle(msg) {
this.processMsg(msg);
}
processMsg(msg) {
this.messageToProcess = msg;
// Resolve dynamic expressions
let splunkHost = App.util.evaluateDynamicField(this.nodeConfig.splunkHost, this.messageToProcess, this);
let splunkPort = App.util.evaluateDynamicField(this.nodeConfig.splunkPort, this.messageToProcess, this);
let hecToken = App.util.evaluateDynamicField(this.nodeConfig.hecToken, this.messageToProcess, this);
let logMessage = App.util.evaluateDynamicField(this.nodeConfig.splunkLogData, this.messageToProcess, this);
// Instantiate splunk logger (lazyily)
let splunkLogger = this.getSplunkLogger({
token: hecToken,
url: `https://${splunkHost}:${splunkPort}`
});
// Send message to console if required
if (this.nodeConfig.consoleOutput) {
let level = this.nodeConfig.level || 'info';
switch (level) {
case 'info': this.info(logMessage); break;
case 'debug': this.debug(logMessage); break;
case 'warn': this.warn(logMessage); break;
case 'error': this.error(logMessage); break;
default: this.log(logMessage);
}
}
// Send message to splunk instance
let metadata = {};
if (this.nodeConfig.metaSource){
metadata.source = App.util.evaluateDynamicField(this.nodeConfig.metaSource, this.messageToProcess, this);
}
if (this.nodeConfig.metaSourceType){
metadata.sourcetype = App.util.evaluateDynamicField(this.nodeConfig.metaSourceType, this.messageToProcess, this);
}
if (this.nodeConfig.metaHost){
metadata.host = App.util.evaluateDynamicField(this.nodeConfig.metaHost, this.messageToProcess, this);
}
if (this.nodeConfig.metaIndex){
metadata.index = App.util.evaluateDynamicField(this.nodeConfig.metaIndex, this.messageToProcess, this);
}
let payload = {
message: logMessage,
severity: this.nodeConfig.level || 'info',
metadata: metadata
}
splunkLogger.send(payload, (error, response, body) => {
if (error) {
if (error.code == 'ETIMEDOUT' || error.code == 'ENOTFOUND') {
this.sendError(new SplunkConnectionError(error), this.messageToProcess);
}
} else if (body && body.text == 'Invalid token') {
this.sendError(new SplunkInvalidTokenError(new Error()), this.messageToProcess);
} else {
if (response && JSON.parse(response.body).text == 'Success') {
this.send(this.messageToProcess);
} else {
this.sendError(new SplunkDataWriteError(new Error()), this.messageToProcess);
}
}
});
}
getSplunkLogger(config) {
let SplunkLogger = require("splunk-logging").Logger;
return new SplunkLogger({
token: config.token,
url: config.url,
maxRetries: 2
});
}
}
App.nodes.registerType('splunk', KumologicaSplunkNode);
};