Skip to content

Instantly share code, notes, and snippets.

@oroce
Last active April 1, 2017 15:12
Show Gist options
  • Save oroce/5076695 to your computer and use it in GitHub Desktop.
Save oroce/5076695 to your computer and use it in GitHub Desktop.
This is just a proof of concept demo to parse haproxy log and put into Google Analytics.

HaProxyLog

This is just a proof of concept demo to parse haproxy log and put into Google Analytics

Howto

  • Run the app.js as sudo on port 514: PORT=514 sudo node app.js

or

  • Run the app.js on port above 1000: PORT=3333 node app.js
  • Modify the the haproxy config: log 127.0.0.1:3333 local0

TODO

  • send google analytics the response times of the site
var haproxyLog = new HaProxyLog({
port: process.env.PORT||3333
});
haproxyLog
.on( "up", console.log.bind( console, "Server is up" ) )
.on( "down", console.log.bind( console, "Server is down" ) )
.on( "backend-down", console.log.bind( console, "Backend is down" ) )
.on( "access-log", console.log.bind( console, "access log entry:" ) )
.on( "raw", function( message ){console.log( "this is the raw message:", message.toString() ) });
/*jshint expr:true*/
var
udp = require( "dgram" ),
util = require( "util" ),
EventEmitter = require( "events" ).EventEmitter;
var HaProxyLog = function _HaProxyLog( options ){
options || ( options = {} );
this.port = options.port;
this.socket = socket = udp.createSocket( "udp4" );
this.bindEvents();
this.listen();
};
util.inherits( HaProxyLog, EventEmitter );
HaProxyLog.prototype.bindEvents = function _HaProxyLogBindEvents(){
this.socket
.on( "message", this.onMessage.bind( this ) )
.on( "error", this.onError.bind( this ) );
};
HaProxyLog.prototype.listen = function _HaProxyLogListen(){
this.socket.bind( this.port );
};
HaProxyLog.prototype.onMessage = function _HaProxyLogOnMessage( message, info ){
this.emit( "raw", message, info );
// decide what type of message
message = message.toString();
var result = this.reType.exec( message );
if( !result ){
return console.warn( "unkown type of message:", message );
}
var
code = result[ 1 ],
fn = this[ this.methodMap[ code ] ];
if( !fn ){
return console.error( "Have no idea what to do with log code:", code, message );
}
fn.apply( this, arguments );
};
HaProxyLog.prototype.onProxyInfo = function _HaProxyLogOnUp( str ){
str = str.toString();
var matches = str.match( this.reServerUpDown );
if( matches ){
this[ "on" + matches[6].charAt( 0 ).toUpperCase() + matches[6].slice( 1 ).toLowerCase() ]( matches );
}
};
HaProxyLog.prototype.onUp = function _HaProxyLogOnUp( result ){
var log = {
date: result[1],
time: result[2],
program: result[3],
backend: result[4],
serverName: result[5],
state: result[6]
};
this.emit( "up", log );
};
HaProxyLog.prototype.onDown = function _HaProxyLogOnUp( result ){
var log = {
date: result[1],
time: result[2],
program: result[3],
backend: result[4],
serverName: result[5],
state: result[6]
};
this.emit( "down", log );
};
HaProxyLog.prototype.onAccessLogEntry = function _HaProxyLogOnAccessLogEntry( str ){
var
result = str.match( this.reAccessLog ),
entry = {
date: result[1],
time: result[2],
program: result[3],
client: result[4],
acceptDate: result[5],
frontendName: result[6],
backendName: result[7],
serverName: result[8],
Tq: +result[9],
Tw: +result[10],
Tc: +result[11],
Tr: +result[12],
Tt: +result[13],
statusCode: +result[14],
bytesRead: +result[15],
capturedReqCookie: result[16],
capturedResCookie: result[17],
terminationState: result[18],
actconn: +result[19],
feconn: +result[20],
beconn: +result[21],
srvConn: +result[22],
retries: +result[23],
srvQueue: +result[24],
backendQueue: +result[25],
method: result[26],
path: result[27],
protocol: result[28]
};
this
.emit( "access-log", entry );
};
HaProxyLog.prototype.onBackendDown = function _HaProxyLogOnBackendDown( str ){
str = str.toString();
var
matches = str.match( this.reBackendDown );
log = {
date: matches[1],
time: matches[2],
program: matches[3],
backend: matches[4]
};
this.emit( "backend-down", log );
};
HaProxyLog.prototype.onError = function _HaProxyLogOnError( err ){};
HaProxyLog.prototype.reAccessLog = /<\d+>(\w+\s+\d{1,2})\s+(\d{1,2}:\d{1,2}:\d{1,2})\s(\w+)\[\d+\]: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)\s\[(.*)\]\s(\w+)\s([a-z0-9_]+)\/([a-z0-9]+)\s(\d+)\/(\d+)\/(\d+)\/(\d+)\/(\d+)\s(\d+)\s(\d+)\s([a-z0-9-_~]+)\s([a-z0-9-_]+)\s([a-z0-9-_]+)\s(\d+)\/(\d+)\/(\d+)\/(\d+)\/(\d+)\s(\d+)\/(\d+)\s"(\w+)\s([a-z\/&?0-9.=-]+)\s([0-9a-z\/.]+)"/i;
HaProxyLog.prototype.reServerUpDown = /<\d+>(\w+\s+\d{1,2})\s+(\d{1,2}:\d{1,2}:\d{1,2})\s(\w+)\[\d+\]:\sServer\s([a-z0-9_]+)\/([a-z0-9]+)\sis\s(DOWN|UP)/;
HaProxyLog.prototype.reBackendDown = /<\d+>(\w+\s+\d{1,2})\s+(\d{1,2}:\d{1,2}:\d{1,2})\s(\w+)\[\d+\]:\sbackend\s([a-z0-9_]+)\shas\sno\sserver\savailable/;
HaProxyLog.prototype.methodMap = {
133: "onProxyInfo",
129: "onProxyInfo",
128: "onBackendDown",
134: "onAccessLogEntry"
};
HaProxyLog.prototype.reType = /^<(\d+)>/;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment