mirror of
https://github.com/raz-varren/sacrificial-socket.git
synced 2025-10-07 00:52:48 +08:00
added more robust logging tools, reconnect options to client js, and angular v1 module
This commit is contained in:
63
client/ng-ss.js
Normal file
63
client/ng-ss.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
(function(window){ 'use strict';
|
||||||
|
if(!window.angular){
|
||||||
|
throw 'angular not loaded';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!window.SS){
|
||||||
|
throw 'sacrificial socket not loaded';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.angular.module('sacrificial-socket', [])
|
||||||
|
.factory('ss', ['$window', '$rootScope', '$log', function($window, $rootScope, $log){
|
||||||
|
function SSNG(url, opts){
|
||||||
|
var self = this,
|
||||||
|
socket = new $window.SS(url, opts);
|
||||||
|
|
||||||
|
self.onConnect = function(callback){
|
||||||
|
callback = callback || socket.noop;
|
||||||
|
socket.onConnect(function(){
|
||||||
|
var args = arguments;
|
||||||
|
$rootScope.$apply(function(){
|
||||||
|
callback.apply(self, args);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onDisconnect = function(callback){
|
||||||
|
callback = callback || socket.noop;
|
||||||
|
socket.onDisconnect(function(){
|
||||||
|
var args = arguments;
|
||||||
|
$rootScope.$apply(function(){
|
||||||
|
callback.apply(self, args);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.on = function(eventName, callback){
|
||||||
|
callback = callback || socket.noop;
|
||||||
|
socket.on(eventName, function(){
|
||||||
|
var args = arguments;
|
||||||
|
$rootScope.$apply(function(){
|
||||||
|
callback.apply(self, args);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.off = function(eventName){
|
||||||
|
return socket.off(eventName);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.emit = function(eventName, data){
|
||||||
|
return socket.emit(eventName, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.close = function(){
|
||||||
|
return socket.close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(url, opts){ return new SSNG(url, opts); };
|
||||||
|
}]);
|
||||||
|
})(window);
|
@@ -5,15 +5,40 @@
|
|||||||
* @class SS
|
* @class SS
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
||||||
|
* @param {Object} opts - connection options
|
||||||
|
*
|
||||||
|
* Default opts = {
|
||||||
|
* reconnectOpts: {
|
||||||
|
* enabled: true,
|
||||||
|
* replayOnConnect: true,
|
||||||
|
* intervalMS: 5000
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
var SS = function(url){
|
var SS = function(url, opts){
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
ws = new WebSocket(url, 'sac-sock'),
|
|
||||||
events = {},
|
events = {},
|
||||||
|
reconnectOpts = {enabled: true, replayOnConnect: true, intervalMS: 5000},
|
||||||
|
reconnecting = false,
|
||||||
|
connectedOnce = false,
|
||||||
headerStartCharCode = 1,
|
headerStartCharCode = 1,
|
||||||
headerStartChar = String.fromCharCode(headerStartCharCode),
|
headerStartChar = String.fromCharCode(headerStartCharCode),
|
||||||
dataStartCharCode = 2,
|
dataStartCharCode = 2,
|
||||||
dataStartChar = String.fromCharCode(dataStartCharCode);
|
dataStartChar = String.fromCharCode(dataStartCharCode),
|
||||||
|
ws = new WebSocket(url, 'sac-sock');
|
||||||
|
|
||||||
|
//we really only support reconnect options for now
|
||||||
|
if(typeof opts.reconnectOpts == 'object'){
|
||||||
|
for(var i in opts.reconnectOpts){
|
||||||
|
if(!opts.reconnectOpts.hasOwnProperty(i)) continue;
|
||||||
|
reconnectOpts[i] = opts.reconnectOpts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.noop = function(){ };
|
||||||
|
|
||||||
//sorry, only supporting arraybuffer at this time
|
//sorry, only supporting arraybuffer at this time
|
||||||
//maybe if there is demand for it, I'll add Blob support
|
//maybe if there is demand for it, I'll add Blob support
|
||||||
@@ -68,29 +93,74 @@
|
|||||||
|
|
||||||
if(eventName.length === 0) return; //no event to dispatch
|
if(eventName.length === 0) return; //no event to dispatch
|
||||||
if(typeof events[eventName] === 'undefined') return;
|
if(typeof events[eventName] === 'undefined') return;
|
||||||
events[eventName]((headers.J) ? JSON.parse(data) : data);
|
events[eventName].call(self, (headers.J) ? JSON.parse(data) : data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* startReconnect is an internal function for reconnecting after an unexpected disconnect
|
||||||
|
*
|
||||||
|
* @function startReconnect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function startReconnect(){
|
||||||
|
setTimeout(function(){
|
||||||
|
console.log('attempting reconnect');
|
||||||
|
var newWS = new WebSocket(url, 'sac-sock');
|
||||||
|
newWS.onmessage = ws.onmessage;
|
||||||
|
newWS.onclose = ws.onclose;
|
||||||
|
newWS.binaryType = ws.binaryType;
|
||||||
|
|
||||||
|
//we need to run the initially set onConnect function on first successful connect,
|
||||||
|
//even if replayOnConnect is disabled. The server might not be available on first
|
||||||
|
//connection attempt.
|
||||||
|
if(reconnectOpts.replayOnConnect || !connectedOnce){
|
||||||
|
newWS.onopen = ws.onopen;
|
||||||
|
}
|
||||||
|
ws = newWS;
|
||||||
|
if(!reconnectOpts.replayOnConnect && connectedOnce){
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
}
|
||||||
|
}, reconnectOpts.intervalMS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onConnect registers a callback to be run when the websocket connection is open.
|
* onConnect registers a callback to be run when the websocket connection is open.
|
||||||
*
|
*
|
||||||
* @method onConnect
|
* @method onConnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection opens.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection opens.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
self.onConnect = function(callback){
|
self.onConnect = function(callback){
|
||||||
ws.onopen = function(){ callback(self); };
|
ws.onopen = function(){
|
||||||
|
connectedOnce = true;
|
||||||
|
var args = arguments;
|
||||||
|
callback.apply(self, args);
|
||||||
|
if(reconnecting){
|
||||||
|
reconnecting = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
||||||
*
|
*
|
||||||
* @method onDisconnect
|
* @method onDisconnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection is closed.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection is closed.
|
||||||
*/
|
*/
|
||||||
self.onDisconnect = function(callback){
|
self.onDisconnect = function(callback){
|
||||||
ws.onclose = function(){ callback(self); };
|
ws.onclose = function(){
|
||||||
|
var args = arguments;
|
||||||
|
if(!reconnecting && connectedOnce){
|
||||||
|
callback.apply(self, args);
|
||||||
|
}
|
||||||
|
if(reconnectOpts.enabled){
|
||||||
|
reconnecting = true;
|
||||||
|
startReconnect();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onDisconnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* on registers an event to be called when the client receives an emit from the server for
|
* on registers an event to be called when the client receives an emit from the server for
|
||||||
@@ -162,6 +232,7 @@
|
|||||||
* @method close
|
* @method close
|
||||||
*/
|
*/
|
||||||
self.close = function(){
|
self.close = function(){
|
||||||
|
reconnectOpts.enabled = false; //don't reconnect if close is called
|
||||||
return ws.close();
|
return ws.close();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -5,15 +5,40 @@
|
|||||||
* @class SS
|
* @class SS
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
||||||
|
* @param {Object} opts - connection options
|
||||||
|
*
|
||||||
|
* Default opts = {
|
||||||
|
* reconnectOpts: {
|
||||||
|
* enabled: true,
|
||||||
|
* replayOnConnect: true,
|
||||||
|
* intervalMS: 5000
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
var SS = function(url){
|
var SS = function(url, opts){
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
ws = new WebSocket(url, 'sac-sock'),
|
|
||||||
events = {},
|
events = {},
|
||||||
|
reconnectOpts = {enabled: true, replayOnConnect: true, intervalMS: 5000},
|
||||||
|
reconnecting = false,
|
||||||
|
connectedOnce = false,
|
||||||
headerStartCharCode = 1,
|
headerStartCharCode = 1,
|
||||||
headerStartChar = String.fromCharCode(headerStartCharCode),
|
headerStartChar = String.fromCharCode(headerStartCharCode),
|
||||||
dataStartCharCode = 2,
|
dataStartCharCode = 2,
|
||||||
dataStartChar = String.fromCharCode(dataStartCharCode);
|
dataStartChar = String.fromCharCode(dataStartCharCode),
|
||||||
|
ws = new WebSocket(url, 'sac-sock');
|
||||||
|
|
||||||
|
//we really only support reconnect options for now
|
||||||
|
if(typeof opts.reconnectOpts == 'object'){
|
||||||
|
for(var i in opts.reconnectOpts){
|
||||||
|
if(!opts.reconnectOpts.hasOwnProperty(i)) continue;
|
||||||
|
reconnectOpts[i] = opts.reconnectOpts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.noop = function(){ };
|
||||||
|
|
||||||
//sorry, only supporting arraybuffer at this time
|
//sorry, only supporting arraybuffer at this time
|
||||||
//maybe if there is demand for it, I'll add Blob support
|
//maybe if there is demand for it, I'll add Blob support
|
||||||
@@ -68,29 +93,74 @@
|
|||||||
|
|
||||||
if(eventName.length === 0) return; //no event to dispatch
|
if(eventName.length === 0) return; //no event to dispatch
|
||||||
if(typeof events[eventName] === 'undefined') return;
|
if(typeof events[eventName] === 'undefined') return;
|
||||||
events[eventName]((headers.J) ? JSON.parse(data) : data);
|
events[eventName].call(self, (headers.J) ? JSON.parse(data) : data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* startReconnect is an internal function for reconnecting after an unexpected disconnect
|
||||||
|
*
|
||||||
|
* @function startReconnect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function startReconnect(){
|
||||||
|
setTimeout(function(){
|
||||||
|
console.log('attempting reconnect');
|
||||||
|
var newWS = new WebSocket(url, 'sac-sock');
|
||||||
|
newWS.onmessage = ws.onmessage;
|
||||||
|
newWS.onclose = ws.onclose;
|
||||||
|
newWS.binaryType = ws.binaryType;
|
||||||
|
|
||||||
|
//we need to run the initially set onConnect function on first successful connect,
|
||||||
|
//even if replayOnConnect is disabled. The server might not be available on first
|
||||||
|
//connection attempt.
|
||||||
|
if(reconnectOpts.replayOnConnect || !connectedOnce){
|
||||||
|
newWS.onopen = ws.onopen;
|
||||||
|
}
|
||||||
|
ws = newWS;
|
||||||
|
if(!reconnectOpts.replayOnConnect && connectedOnce){
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
}
|
||||||
|
}, reconnectOpts.intervalMS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onConnect registers a callback to be run when the websocket connection is open.
|
* onConnect registers a callback to be run when the websocket connection is open.
|
||||||
*
|
*
|
||||||
* @method onConnect
|
* @method onConnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection opens.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection opens.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
self.onConnect = function(callback){
|
self.onConnect = function(callback){
|
||||||
ws.onopen = function(){ callback(self); };
|
ws.onopen = function(){
|
||||||
|
connectedOnce = true;
|
||||||
|
var args = arguments;
|
||||||
|
callback.apply(self, args);
|
||||||
|
if(reconnecting){
|
||||||
|
reconnecting = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
||||||
*
|
*
|
||||||
* @method onDisconnect
|
* @method onDisconnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection is closed.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection is closed.
|
||||||
*/
|
*/
|
||||||
self.onDisconnect = function(callback){
|
self.onDisconnect = function(callback){
|
||||||
ws.onclose = function(){ callback(self); };
|
ws.onclose = function(){
|
||||||
|
var args = arguments;
|
||||||
|
if(!reconnecting && connectedOnce){
|
||||||
|
callback.apply(self, args);
|
||||||
|
}
|
||||||
|
if(reconnectOpts.enabled){
|
||||||
|
reconnecting = true;
|
||||||
|
startReconnect();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onDisconnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* on registers an event to be called when the client receives an emit from the server for
|
* on registers an event to be called when the client receives an emit from the server for
|
||||||
@@ -162,6 +232,7 @@
|
|||||||
* @method close
|
* @method close
|
||||||
*/
|
*/
|
||||||
self.close = function(){
|
self.close = function(){
|
||||||
|
reconnectOpts.enabled = false; //don't reconnect if close is called
|
||||||
return ws.close();
|
return ws.close();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -5,15 +5,40 @@
|
|||||||
* @class SS
|
* @class SS
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
* @param {String} url - The url to the sacrificial-socket server endpoint. The url must conform to the websocket URI Scheme ("ws" or "wss")
|
||||||
|
* @param {Object} opts - connection options
|
||||||
|
*
|
||||||
|
* Default opts = {
|
||||||
|
* reconnectOpts: {
|
||||||
|
* enabled: true,
|
||||||
|
* replayOnConnect: true,
|
||||||
|
* intervalMS: 5000
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
var SS = function(url){
|
var SS = function(url, opts){
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
ws = new WebSocket(url, 'sac-sock'),
|
|
||||||
events = {},
|
events = {},
|
||||||
|
reconnectOpts = {enabled: true, replayOnConnect: true, intervalMS: 5000},
|
||||||
|
reconnecting = false,
|
||||||
|
connectedOnce = false,
|
||||||
headerStartCharCode = 1,
|
headerStartCharCode = 1,
|
||||||
headerStartChar = String.fromCharCode(headerStartCharCode),
|
headerStartChar = String.fromCharCode(headerStartCharCode),
|
||||||
dataStartCharCode = 2,
|
dataStartCharCode = 2,
|
||||||
dataStartChar = String.fromCharCode(dataStartCharCode);
|
dataStartChar = String.fromCharCode(dataStartCharCode),
|
||||||
|
ws = new WebSocket(url, 'sac-sock');
|
||||||
|
|
||||||
|
//we really only support reconnect options for now
|
||||||
|
if(typeof opts.reconnectOpts == 'object'){
|
||||||
|
for(var i in opts.reconnectOpts){
|
||||||
|
if(!opts.reconnectOpts.hasOwnProperty(i)) continue;
|
||||||
|
reconnectOpts[i] = opts.reconnectOpts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.noop = function(){ };
|
||||||
|
|
||||||
//sorry, only supporting arraybuffer at this time
|
//sorry, only supporting arraybuffer at this time
|
||||||
//maybe if there is demand for it, I'll add Blob support
|
//maybe if there is demand for it, I'll add Blob support
|
||||||
@@ -68,29 +93,74 @@
|
|||||||
|
|
||||||
if(eventName.length === 0) return; //no event to dispatch
|
if(eventName.length === 0) return; //no event to dispatch
|
||||||
if(typeof events[eventName] === 'undefined') return;
|
if(typeof events[eventName] === 'undefined') return;
|
||||||
events[eventName]((headers.J) ? JSON.parse(data) : data);
|
events[eventName].call(self, (headers.J) ? JSON.parse(data) : data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* startReconnect is an internal function for reconnecting after an unexpected disconnect
|
||||||
|
*
|
||||||
|
* @function startReconnect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function startReconnect(){
|
||||||
|
setTimeout(function(){
|
||||||
|
console.log('attempting reconnect');
|
||||||
|
var newWS = new WebSocket(url, 'sac-sock');
|
||||||
|
newWS.onmessage = ws.onmessage;
|
||||||
|
newWS.onclose = ws.onclose;
|
||||||
|
newWS.binaryType = ws.binaryType;
|
||||||
|
|
||||||
|
//we need to run the initially set onConnect function on first successful connect,
|
||||||
|
//even if replayOnConnect is disabled. The server might not be available on first
|
||||||
|
//connection attempt.
|
||||||
|
if(reconnectOpts.replayOnConnect || !connectedOnce){
|
||||||
|
newWS.onopen = ws.onopen;
|
||||||
|
}
|
||||||
|
ws = newWS;
|
||||||
|
if(!reconnectOpts.replayOnConnect && connectedOnce){
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
}
|
||||||
|
}, reconnectOpts.intervalMS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onConnect registers a callback to be run when the websocket connection is open.
|
* onConnect registers a callback to be run when the websocket connection is open.
|
||||||
*
|
*
|
||||||
* @method onConnect
|
* @method onConnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection opens.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection opens.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
self.onConnect = function(callback){
|
self.onConnect = function(callback){
|
||||||
ws.onopen = function(){ callback(self); };
|
ws.onopen = function(){
|
||||||
|
connectedOnce = true;
|
||||||
|
var args = arguments;
|
||||||
|
callback.apply(self, args);
|
||||||
|
if(reconnecting){
|
||||||
|
reconnecting = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onConnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
* onDisconnect registers a callback to be run when the websocket connection is closed.
|
||||||
*
|
*
|
||||||
* @method onDisconnect
|
* @method onDisconnect
|
||||||
* @param {Function} callback(SS) - The callback that will be executed when the websocket connection is closed.
|
* @param {Function} callback(event) - The callback that will be executed when the websocket connection is closed.
|
||||||
*/
|
*/
|
||||||
self.onDisconnect = function(callback){
|
self.onDisconnect = function(callback){
|
||||||
ws.onclose = function(){ callback(self); };
|
ws.onclose = function(){
|
||||||
|
var args = arguments;
|
||||||
|
if(!reconnecting && connectedOnce){
|
||||||
|
callback.apply(self, args);
|
||||||
|
}
|
||||||
|
if(reconnectOpts.enabled){
|
||||||
|
reconnecting = true;
|
||||||
|
startReconnect();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
self.onDisconnect(self.noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* on registers an event to be called when the client receives an emit from the server for
|
* on registers an event to be called when the client receives an emit from the server for
|
||||||
@@ -162,6 +232,7 @@
|
|||||||
* @method close
|
* @method close
|
||||||
*/
|
*/
|
||||||
self.close = function(){
|
self.close = function(){
|
||||||
|
reconnectOpts.enabled = false; //don't reconnect if close is called
|
||||||
return ws.close();
|
return ws.close();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
152
log/json.go
Normal file
152
log/json.go
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jLog struct {
|
||||||
|
Timestamp time.Time `json:"ts"`
|
||||||
|
File string `json:"file"`
|
||||||
|
Line int `json:"line"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Fatal bool `json:"fatal"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jl *jLog) Marshal() []byte {
|
||||||
|
data, err := json.Marshal(jl)
|
||||||
|
if err != nil {
|
||||||
|
return []byte(fmt.Sprintf(`{"Error":"%s", "Line": %d, "File":"%s"}`, err, jl.Line, jl.File))
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonLogFmt struct {
|
||||||
|
out io.Writer
|
||||||
|
logLevel int
|
||||||
|
logLevelAllowed int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) canLog() bool {
|
||||||
|
return (j.logLevel & j.logLevelAllowed) == j.logLevelAllowed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) writeJLog(msg string, fatal bool) {
|
||||||
|
jl := newJLog(msg, LogLevelMap[j.logLevelAllowed], fatal, 3)
|
||||||
|
data := jl.Marshal()
|
||||||
|
j.out.Write(append(data, '\n'))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJLog(msg, level string, fatal bool, callDepth int) *jLog {
|
||||||
|
jl := &jLog{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Level: level,
|
||||||
|
Fatal: fatal,
|
||||||
|
Msg: msg,
|
||||||
|
}
|
||||||
|
_, file, line, ok := runtime.Caller(callDepth)
|
||||||
|
|
||||||
|
jl.File = file
|
||||||
|
jl.Line = line
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
jl.File = "???"
|
||||||
|
jl.Line = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return jl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Print(v ...interface{}) {
|
||||||
|
if !j.canLog() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg, fatal := fmt.Sprint(v...), false
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Printf(format string, v ...interface{}) {
|
||||||
|
if !j.canLog() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, fatal := fmt.Sprintf(format, v...), false
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Println(v ...interface{}) {
|
||||||
|
if !j.canLog() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, fatal := fmt.Sprintln(v...), false
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Fatal(v ...interface{}) {
|
||||||
|
msg, fatal := fmt.Sprint(v...), true
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Fatalf(format string, v ...interface{}) {
|
||||||
|
msg, fatal := fmt.Sprintf(format, v...), true
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *jsonLogFmt) Fatalln(v ...interface{}) {
|
||||||
|
msg, fatal := fmt.Sprintln(v...), true
|
||||||
|
msg = strings.TrimRight(msg, "\n")
|
||||||
|
|
||||||
|
j.writeJLog(msg, fatal)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJSONLogger(out io.Writer, logLevel int) *Logger {
|
||||||
|
info := &jsonLogFmt{
|
||||||
|
out: out,
|
||||||
|
logLevel: logLevel,
|
||||||
|
logLevelAllowed: LogLevelINFO,
|
||||||
|
}
|
||||||
|
|
||||||
|
warn := &jsonLogFmt{
|
||||||
|
out: out,
|
||||||
|
logLevel: logLevel,
|
||||||
|
logLevelAllowed: LogLevelWARN,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := &jsonLogFmt{
|
||||||
|
out: out,
|
||||||
|
logLevel: logLevel,
|
||||||
|
logLevelAllowed: LogLevelERR,
|
||||||
|
}
|
||||||
|
|
||||||
|
debug := &jsonLogFmt{
|
||||||
|
out: out,
|
||||||
|
logLevel: logLevel,
|
||||||
|
logLevelAllowed: LogLevelDEBUG,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Logger{
|
||||||
|
Info: info,
|
||||||
|
Warn: warn,
|
||||||
|
Err: err,
|
||||||
|
Debug: debug,
|
||||||
|
}
|
||||||
|
}
|
63
log/log.go
63
log/log.go
@@ -1,19 +1,62 @@
|
|||||||
/*
|
|
||||||
Package log is used all throughout Sacrificial Socket for logging info and error messages
|
|
||||||
*/
|
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
l "log"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Err = l.New(os.Stderr, "ERROR: ", l.Ldate|l.Ltime|l.Lshortfile)
|
const (
|
||||||
var Info = l.New(os.Stdout, "INFO: ", l.Ldate|l.Ltime)
|
LogLevelINFO = 1 << iota
|
||||||
|
LogLevelWARN
|
||||||
|
LogLevelERR
|
||||||
|
LogLevelDEBUG
|
||||||
|
|
||||||
func CheckFatal(err error) {
|
LogLevelNone = 0
|
||||||
if err != nil {
|
LogLevelStd = LogLevelINFO | LogLevelWARN | LogLevelERR
|
||||||
Err.Output(2, err.Error())
|
LogLevelWarn = LogLevelWARN | LogLevelERR
|
||||||
os.Exit(1)
|
LogLevelErr = LogLevelERR
|
||||||
|
LogLevelDbg = LogLevelStd | LogLevelDEBUG
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultLogger = NewColorLogger(os.Stdout, LogLevelDbg)
|
||||||
|
|
||||||
|
Info = defaultLogger.Info
|
||||||
|
Warn = defaultLogger.Warn
|
||||||
|
Err = defaultLogger.Err
|
||||||
|
Debug = defaultLogger.Debug
|
||||||
|
|
||||||
|
LogLevelMap = map[int]string{
|
||||||
|
LogLevelINFO: "INFO",
|
||||||
|
LogLevelWARN: "WARN",
|
||||||
|
LogLevelERR: "ERROR",
|
||||||
|
LogLevelDEBUG: "DEBUG",
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//this is pretty much the only thing that isn't
|
||||||
|
//safe to run in multiple go routines, you should
|
||||||
|
//call SetDefaultLogger at the beginning of your main function
|
||||||
|
func SetDefaultLogger(l *Logger) {
|
||||||
|
defaultLogger = l
|
||||||
|
Info = defaultLogger.Info
|
||||||
|
Warn = defaultLogger.Warn
|
||||||
|
Err = defaultLogger.Err
|
||||||
|
Debug = defaultLogger.Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogFormatter interface {
|
||||||
|
Fatal(v ...interface{})
|
||||||
|
Fatalf(format string, v ...interface{})
|
||||||
|
Fatalln(v ...interface{})
|
||||||
|
|
||||||
|
Print(v ...interface{})
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
Println(v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
Info LogFormatter
|
||||||
|
Warn LogFormatter
|
||||||
|
Err LogFormatter
|
||||||
|
Debug LogFormatter
|
||||||
}
|
}
|
||||||
|
177
log/std-out.go
Normal file
177
log/std-out.go
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
goLog "log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
colorLogDepth = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ansiColorPallet = map[string][]byte{
|
||||||
|
"none": []byte("\x1b[0m"),
|
||||||
|
"black": []byte("\x1b[0;30m"),
|
||||||
|
"red": []byte("\x1b[0;31m"),
|
||||||
|
"green": []byte("\x1b[0;32m"),
|
||||||
|
"orange": []byte("\x1b[0;33m"),
|
||||||
|
"blue": []byte("\x1b[0;34m"),
|
||||||
|
"purple": []byte("\x1b[0;35m"),
|
||||||
|
"cyan": []byte("\x1b[0;36m"),
|
||||||
|
"light-gray": []byte("\x1b[0;37m"),
|
||||||
|
"dark-gray": []byte("\x1b[1;30m"),
|
||||||
|
"light-red": []byte("\x1b[1;31m"),
|
||||||
|
"light-green": []byte("\x1b[1;32m"),
|
||||||
|
"yellow": []byte("\x1b[1;33m"),
|
||||||
|
"light-blue": []byte("\x1b[1;34m"),
|
||||||
|
"light-purple": []byte("\x1b[1;35m"),
|
||||||
|
"light-cyan": []byte("\x1b[1;36m"),
|
||||||
|
"white": []byte("\x1b[1;37m"),
|
||||||
|
}
|
||||||
|
|
||||||
|
logColors = map[int][]byte{
|
||||||
|
LogLevelINFO: ansiColorPallet["white"],
|
||||||
|
LogLevelWARN: ansiColorPallet["orange"],
|
||||||
|
LogLevelERR: ansiColorPallet["red"],
|
||||||
|
LogLevelDEBUG: ansiColorPallet["light-blue"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewColorLogger(out io.Writer, logLevel int) *Logger {
|
||||||
|
return newLogger(out, logLevel, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger(out io.Writer, logLevel int) *Logger {
|
||||||
|
return newLogger(out, logLevel, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLogger(out io.Writer, logLevel int, color bool) *Logger {
|
||||||
|
logger := &Logger{
|
||||||
|
Info: newColorLogFmt(out, logLevel, LogLevelINFO, color),
|
||||||
|
Warn: newColorLogFmt(out, logLevel, LogLevelWARN, color),
|
||||||
|
Err: newColorLogFmt(out, logLevel, LogLevelERR, color),
|
||||||
|
Debug: newColorLogFmt(out, logLevel, LogLevelDEBUG, color),
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type colorLogFmt struct {
|
||||||
|
out io.Writer
|
||||||
|
logger *goLog.Logger
|
||||||
|
logLevel int
|
||||||
|
fmtLevel int
|
||||||
|
color bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newColorLogFmt(out io.Writer, logLevel, fmtLevel int, color bool) *colorLogFmt {
|
||||||
|
clf := &colorLogFmt{
|
||||||
|
logLevel: logLevel,
|
||||||
|
fmtLevel: fmtLevel,
|
||||||
|
out: out,
|
||||||
|
color: color,
|
||||||
|
}
|
||||||
|
lFlags := goLog.LstdFlags
|
||||||
|
|
||||||
|
if fmtLevel != LogLevelINFO {
|
||||||
|
lFlags |= goLog.Lshortfile
|
||||||
|
}
|
||||||
|
clf.logger = goLog.New(out, padStr(LogLevelMap[fmtLevel], 6), lFlags)
|
||||||
|
|
||||||
|
return clf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) canLog() bool {
|
||||||
|
return (lf.logLevel & lf.fmtLevel) == lf.fmtLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) doOutput(pType, format string, v ...interface{}) {
|
||||||
|
switch pType {
|
||||||
|
case "Print", "Fatal":
|
||||||
|
lf.logger.Output(colorLogDepth, fmt.Sprint(v...))
|
||||||
|
case "Printf", "Fatalf":
|
||||||
|
lf.logger.Output(colorLogDepth, fmt.Sprintf(format, v...))
|
||||||
|
case "Println", "Fatalln":
|
||||||
|
lf.logger.Output(colorLogDepth, fmt.Sprintln(v...))
|
||||||
|
default:
|
||||||
|
lf.logger.Output(colorLogDepth, fmt.Sprint(v...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) doPrint(pType, format string, v ...interface{}) {
|
||||||
|
switch pType {
|
||||||
|
case "Fatal", "Fatalf", "Fatalln":
|
||||||
|
lf.setErrColor()
|
||||||
|
lf.doOutput(pType, format, v...)
|
||||||
|
lf.dropColor()
|
||||||
|
os.Exit(1)
|
||||||
|
case "Print", "Printf", "Println":
|
||||||
|
if !lf.canLog() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lf.setFmtColor()
|
||||||
|
lf.doOutput(pType, format, v...)
|
||||||
|
lf.dropColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fatal logs don't care what the logLevel is. They print
|
||||||
|
//and exit with a satus of 1
|
||||||
|
func (lf *colorLogFmt) Fatal(v ...interface{}) {
|
||||||
|
lf.doPrint("Fatal", "", v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) Fatalf(format string, v ...interface{}) {
|
||||||
|
lf.doPrint("Fatalf", format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) Fatalln(v ...interface{}) {
|
||||||
|
lf.doPrint("Fatalln", "", v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) Print(v ...interface{}) {
|
||||||
|
lf.doPrint("Print", "", v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) Printf(format string, v ...interface{}) {
|
||||||
|
lf.doPrint("Printf", format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) Println(v ...interface{}) {
|
||||||
|
lf.doPrint("Println", "", v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) setColor(color []byte) {
|
||||||
|
if !lf.color {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lf.out.Write(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) setErrColor() {
|
||||||
|
lf.setColor(logColors[LogLevelERR])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) setFmtColor() {
|
||||||
|
lf.setColor(logColors[lf.fmtLevel])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lf *colorLogFmt) dropColor() {
|
||||||
|
lf.setColor(ansiColorPallet["none"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func padStr(s string, length int) string {
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
b.WriteString(s)
|
||||||
|
for {
|
||||||
|
if b.Len() >= length {
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
b.WriteString(" ")
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user