Robochameleon  v1.0
robolog.m
Go to the documentation of this file.
1 
2 function robolog(msg, varargin)
3 %Constants
4 validLogTypeValues = {'ERR', 'WRN', 'DBG', 'NFO', 'NFO0'};
5 textColors = {[1 0 0], [1, 0.5, 0], [0 0.7 1],[0 0 0], [0 0 0]}; % Black, orange, red, cyan
6 
7 % Get global preferences
8 persistent logToFile
9 persistent logFile
10 persistent logLevel
11 persistent logInBlack
12 if isempty(logToFile)
13  logToFile=getpref('roboLog', 'logToFile', false);
14  logFile=getpref('roboLog', 'logFile', 'robolog.txt');
15  logLevel=getpref('roboLog','logLevel', length(validLogTypeValues));
16  logInBlack=getpref('roboLog','logInBlack', 0);
17 end
18 
19 if logLevel < 1
20  error('Robochameleon log level must be >= 1');
21 end
22 %The second argument is the log type, check if it's valid.
23 %If not specified assume NFO level
24 isValid=0;
25 if nargin > 1 && ischar(varargin{1})
26  [isValid, logTypeIdx] = ismember(varargin{1}, validLogTypeValues);
27  if isValid
28  logType = varargin{1};
29  argIdx = 2;
30  end
31 end
32 
33 if nargin == 1 || ~isValid
34  logType = 'NFO';
35  logTypeIdx = find(strcmp(validLogTypeValues,logType));
36  argIdx = 1;
37 end
38 
39 %Check the logLevel to know if we need to log this message
40 if logTypeIdx > logLevel
41  return
42 end
43 
44 %Get the name of the caller function
45 db = dbstack(1);
46 if ~isempty(db)
47  callerName = strsplit(db(1).name, '.');
48  callerName = callerName(1);
49  callerName = callerName{:};
50 else
51  % the caller is a script not a function
52  callerName='main script';
53 end
54 
55 % if caller is unit, rather use the actual unit
56 if strcmpi(callerName,'unit')
57  callerName = evalin('caller','class(obj)');
58 end
59 
60 %Double escape % and \ because we call sprintf twice
61 msg = strrep(msg, '%%', '%%%%');
62 msg = strrep(msg, '\\', '\\\\');
63 %Perform the logging
64 %If we have more than one arguments, all the arguments from the argidx are
65 %parameters for printf
66 if nargin > 1
67  %What is passed as string argument to robolog (%s) should be treated as string
68  %but since we are passing it into sprintf twice we need to escape % and \\.
69  %There cannot be escape sequences into the string arguments.
70  idx = cellfun(@isstr, varargin);
71  varargin(idx) = strrep(varargin(idx), '%', '%%');
72  varargin(idx) = strrep(varargin(idx), '\', '\\');
73  msg=sprintf(['(Robo %s)\tIn %s: ', msg], logType, callerName, varargin{argIdx:end});
74 else
75  msg=sprintf(['(Robo %s)\tIn %s: ', msg], logType, callerName);
76 end
77 
78 %Detect newlines and align subsequent lines vertically to the first one by adding spaces
79 %Warning: We are passing the message two times through printf:
80 % \n > newline > remains newline (Should work, needs testing)
81 % What happens if we escape more? \\n \\\n \\\\n? Wierd things (Don't do it)
82 prefixLength = 16; % length('(Robo NFO) In : ')
83 spacedNewLine = ['\n' repmat(' ', 1, prefixLength + length(callerName))];
84 logMsg = strrep(msg, sprintf('\n'), spacedNewLine);
85 logMsg = [logMsg '\n'];
86 
87 %If we need to log to file, we open it in append mode
88 if logToFile
89  fileId = fopen(logFile, 'a');
90  fprintf(fileId, logMsg);
91  fclose(fileId);
92 end
93 
94 %If the log type is an error, launch an error and break the code execution
95 if strcmp(logType, 'ERR')
96  me = MException('robochameleon:genericError', logMsg);
97  throwAsCaller(me);
98 else
99 
100 % Log to console if logToFile is 0 or 2 (log both on file and terminal)
101 if logToFile == 2 || logToFile == 0
102  if strcmp(logType, 'NFO') || logInBlack
103  fprintf(1, logMsg);
104  else
105  cprintf(textColors{logTypeIdx}, logMsg);
106  end
107 end
108 
109 end
Superclass: basic building block to hold functions.
Definition: unit.m:27
function robolog(in msg, in varargin)
This function allows the user to print log messages in a standard way.
function robochameleon(in varargin)
Add robochameleon related directories to the MATLAB path.