mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 11:07:48 +00:00
321 lines
8.9 KiB
Matlab
321 lines
8.9 KiB
Matlab
|
|
classdef logging < handle
|
||
|
|
%LOGGING Simple logging framework.
|
||
|
|
%
|
||
|
|
% Author:
|
||
|
|
% Dominique Orban <dominique.orban@gmail.com>
|
||
|
|
% Heavily modified version of 'log4m': http://goo.gl/qDUcvZ
|
||
|
|
%
|
||
|
|
|
||
|
|
properties (Constant)
|
||
|
|
ALL = int8(0);
|
||
|
|
TRACE = int8(1);
|
||
|
|
DEBUG = int8(2);
|
||
|
|
INFO = int8(3);
|
||
|
|
WARNING = int8(4);
|
||
|
|
ERROR = int8(5);
|
||
|
|
CRITICAL = int8(6);
|
||
|
|
OFF = int8(7);
|
||
|
|
|
||
|
|
colors_terminal = containers.Map(...
|
||
|
|
{'normal', 'red', 'green', 'yellow', 'blue', 'brightred'}, ...
|
||
|
|
{'%s', '\033[31m%s\033[0m', '\033[32m%s\033[0m', '\033[33m%s\033[0m', ...
|
||
|
|
'\033[34m%s\033[0m', '\033[1;31m%s\033[0m'});
|
||
|
|
|
||
|
|
level_colors = containers.Map(...
|
||
|
|
{logging.logging.INFO, logging.logging.ERROR, logging.logging.TRACE, ...
|
||
|
|
logging.logging.WARNING, logging.logging.DEBUG, logging.logging.CRITICAL}, ...
|
||
|
|
{'normal', 'red', 'green', 'yellow', 'blue', 'brightred'});
|
||
|
|
|
||
|
|
levels = containers.Map(...
|
||
|
|
{logging.logging.ALL, logging.logging.TRACE, logging.logging.DEBUG, ...
|
||
|
|
logging.logging.INFO, logging.logging.WARNING, logging.logging.ERROR, ...
|
||
|
|
logging.logging.CRITICAL, logging.logging.OFF}, ...
|
||
|
|
{'ALL', 'TRACE', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'OFF'});
|
||
|
|
end
|
||
|
|
|
||
|
|
properties (SetAccess=immutable)
|
||
|
|
level_numbers;
|
||
|
|
level_range;
|
||
|
|
end
|
||
|
|
|
||
|
|
properties (SetAccess=protected)
|
||
|
|
name;
|
||
|
|
fullpath = 'logging.log'; % Default log file
|
||
|
|
logfmt = '%-23s %-40s %-8s %s\n'; % Default LogFormat
|
||
|
|
logfid = -1;
|
||
|
|
logcolors = logging.logging.colors_terminal;
|
||
|
|
using_terminal;
|
||
|
|
webhook;
|
||
|
|
instance;
|
||
|
|
end
|
||
|
|
|
||
|
|
properties (Hidden,SetAccess=protected)
|
||
|
|
datefmt_ = 'yyyy-mm-dd HH:MM:SS,FFF';
|
||
|
|
logLevel_ = logging.logging.INFO;
|
||
|
|
commandWindowLevel_ = logging.logging.INFO;
|
||
|
|
end
|
||
|
|
|
||
|
|
properties (Dependent)
|
||
|
|
datefmt;
|
||
|
|
logLevel;
|
||
|
|
commandWindowLevel;
|
||
|
|
end
|
||
|
|
|
||
|
|
methods(Static)
|
||
|
|
function [name, line] = getCallerInfo(self)
|
||
|
|
|
||
|
|
if nargin > 0 && self.ignoreLogging()
|
||
|
|
name = [];
|
||
|
|
line = [];
|
||
|
|
return
|
||
|
|
end
|
||
|
|
[ST, ~] = dbstack();
|
||
|
|
offset = min(size(ST, 1), 3);
|
||
|
|
name = ST(offset).name;
|
||
|
|
line = ST(offset).line;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
methods
|
||
|
|
|
||
|
|
function setFilename(self, logPath)
|
||
|
|
[self.logfid, message] = fopen(logPath, 'a');
|
||
|
|
|
||
|
|
if self.logfid < 0
|
||
|
|
warning(['Problem with supplied logfile path: ' message]);
|
||
|
|
self.logLevel_ = logging.logging.OFF;
|
||
|
|
end
|
||
|
|
|
||
|
|
self.fullpath = logPath;
|
||
|
|
end
|
||
|
|
|
||
|
|
function setCommandWindowLevel(self, level)
|
||
|
|
self.commandWindowLevel = level;
|
||
|
|
end
|
||
|
|
|
||
|
|
function setLogLevel(self, level)
|
||
|
|
self.logLevel = level;
|
||
|
|
end
|
||
|
|
|
||
|
|
function setSlackWebHook(self, WebHook)
|
||
|
|
self.webhook = WebHook;
|
||
|
|
end
|
||
|
|
function setSlackInstance(self, Instance)
|
||
|
|
self.instance = Instance;
|
||
|
|
end
|
||
|
|
function tf = ignoreLogging(self)
|
||
|
|
tf = self.commandWindowLevel_ == self.OFF && self.logLevel_ == self.OFF;
|
||
|
|
end
|
||
|
|
|
||
|
|
function trace(self, message,varargin)
|
||
|
|
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.TRACE, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function debug(self, message,varargin)
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.DEBUG, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function info(self, message,varargin)
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.INFO, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function warn(self, message,varargin)
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.WARNING, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function error(self, message,varargin)
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.ERROR, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function critical(self, message,varargin)
|
||
|
|
sendtoslack = 0;
|
||
|
|
if (nargin == 3 )
|
||
|
|
if varargin{1,1} == 1
|
||
|
|
sendtoslack = 1;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
[caller_name, ~] = self.getCallerInfo(self);
|
||
|
|
self.writeLog(self.CRITICAL, caller_name, message,sendtoslack);
|
||
|
|
end
|
||
|
|
|
||
|
|
function self = logging(name, varargin)
|
||
|
|
levelkeys = self.levels.keys;
|
||
|
|
self.level_numbers = containers.Map(self.levels.values, levelkeys);
|
||
|
|
levelkeys = cell2mat(self.levels.keys);
|
||
|
|
self.level_range = [min(levelkeys), max(levelkeys)];
|
||
|
|
|
||
|
|
p = inputParser();
|
||
|
|
p.addRequired('name', @ischar);
|
||
|
|
p.addParameter('path', '', @ischar);
|
||
|
|
p.addParameter('logLevel', self.logLevel);
|
||
|
|
p.addParameter('commandWindowLevel', self.commandWindowLevel);
|
||
|
|
p.addParameter('datefmt', self.datefmt_);
|
||
|
|
p.parse(name, varargin{:});
|
||
|
|
r = p.Results;
|
||
|
|
|
||
|
|
self.name = r.name;
|
||
|
|
self.commandWindowLevel = r.commandWindowLevel;
|
||
|
|
self.datefmt = r.datefmt;
|
||
|
|
if ~isempty(r.path)
|
||
|
|
self.setFilename(r.path); % Opens the log file.
|
||
|
|
self.logLevel = r.logLevel;
|
||
|
|
else
|
||
|
|
self.logLevel_ = logging.logging.OFF;
|
||
|
|
end
|
||
|
|
% Use terminal logging if swing is disabled in matlab environment.
|
||
|
|
swingError = javachk('swing');
|
||
|
|
self.using_terminal = (~ isempty(swingError) && strcmp(swingError.identifier, 'MATLAB:javachk:thisFeatureNotAvailable')) || ~desktop('-inuse');
|
||
|
|
end
|
||
|
|
|
||
|
|
function delete(self)
|
||
|
|
if self.logfid > -1
|
||
|
|
fclose(self.logfid);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function writeLog(self, level, caller, message, sendtoslack)
|
||
|
|
level = self.getLevelNumber(level);
|
||
|
|
if self.commandWindowLevel_ <= level || self.logLevel_ <= level
|
||
|
|
timestamp = datestr(now, self.datefmt_);
|
||
|
|
levelStr = logging.logging.levels(level);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
logline = sprintf(self.logfmt, timestamp, caller, levelStr, self.getMessage(message));
|
||
|
|
end
|
||
|
|
|
||
|
|
if sendtoslack
|
||
|
|
|
||
|
|
level = self.getLevelNumber(level);
|
||
|
|
|
||
|
|
timestamp = datestr(now, self.datefmt_);
|
||
|
|
levelStr = logging.logging.levels(level);
|
||
|
|
|
||
|
|
|
||
|
|
slacklogline = sprintf(self.logfmt, timestamp, caller, levelStr, self.getMessage(message));
|
||
|
|
|
||
|
|
SendSlackNotification(self.webhook,strcat(self.instance,' : ', slacklogline));
|
||
|
|
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
if self.commandWindowLevel_ <= level
|
||
|
|
if self.using_terminal
|
||
|
|
level_color = self.level_colors(level);
|
||
|
|
else
|
||
|
|
level_color = self.level_colors(logging.logging.INFO);
|
||
|
|
end
|
||
|
|
fprintf(self.logcolors(level_color), logline);
|
||
|
|
end
|
||
|
|
|
||
|
|
if self.logLevel_ <= level && self.logfid > -1
|
||
|
|
fprintf(self.logfid, logline);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function set.datefmt(self, fmt)
|
||
|
|
try
|
||
|
|
datestr(now(), fmt);
|
||
|
|
catch
|
||
|
|
error('Invalid date format');
|
||
|
|
end
|
||
|
|
self.datefmt_ = fmt;
|
||
|
|
end
|
||
|
|
|
||
|
|
function fmt = get.datefmt(self)
|
||
|
|
fmt = self.datefmt_;
|
||
|
|
end
|
||
|
|
|
||
|
|
function set.logLevel(self, level)
|
||
|
|
level = self.getLevelNumber(level);
|
||
|
|
if level > logging.logging.OFF || level < logging.logging.ALL
|
||
|
|
error('invalid logging level');
|
||
|
|
end
|
||
|
|
self.logLevel_ = level;
|
||
|
|
end
|
||
|
|
|
||
|
|
function level = get.logLevel(self)
|
||
|
|
level = self.logLevel_;
|
||
|
|
end
|
||
|
|
|
||
|
|
function set.commandWindowLevel(self, level)
|
||
|
|
self.commandWindowLevel_ = self.getLevelNumber(level);
|
||
|
|
end
|
||
|
|
|
||
|
|
function level = get.commandWindowLevel(self)
|
||
|
|
level = self.commandWindowLevel_;
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
methods (Hidden)
|
||
|
|
function level = getLevelNumber(self, level)
|
||
|
|
% LEVEL = GETLEVELNUMBER(LEVEL)
|
||
|
|
%
|
||
|
|
% Converts charecter-based level names to level numbers
|
||
|
|
% used internally by logging.
|
||
|
|
%
|
||
|
|
% If given a number, it makes sure the number is valid
|
||
|
|
% then returns it unchanged.
|
||
|
|
%
|
||
|
|
% This allows users to specify levels by name or number.
|
||
|
|
if isinteger(level) && self.level_range(1) <= level && level <= self.level_range(2)
|
||
|
|
return
|
||
|
|
else
|
||
|
|
level = self.level_numbers(level);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function message = getMessage(~, message)
|
||
|
|
|
||
|
|
if isa(message, 'function_handle')
|
||
|
|
message = message();
|
||
|
|
end
|
||
|
|
[rows, ~] = size(message);
|
||
|
|
if rows > 1
|
||
|
|
message = sprintf('\n %s', evalc('disp(message)'));
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
end
|