MatrixBerryCore
DataLogger.m
Go to the documentation of this file.
1 classdef DataLogger<mxberry.core.obj.StaticPropStorage
2 
3  methods (Static)
4  function configure(varargin)
5 
6  import org.apache.log4j.Logger;
7  className=mfilename('class');
8  feval([className '.flush']);
9  %% default values for properties
10  storageLocation=[fileparts(which(className)) filesep 'DataLogs'];
11  isEnabled=false;
12  functionNameList=cell(1,0);
13  nMaxDatesOnDisk=5;
14  %% parse properties
15  [~,prop]=mxberry.core.parseparams(varargin,[],0);
16  nProp=length(prop);
17  for iProp=1:2:nProp-1
18  switch lower(prop{iProp})
19  case 'isenabled'
20  isEnabled=prop{iProp+1};
21  case 'functionnamelist'
22  functionNameList=prop{iProp+1};
23  case 'storagelocationroot'
24  storageLocation=prop{iProp+1};
25  case 'nmaxdatesondisk'
26  nMaxDatesOnDisk=prop{iProp+1};
27  otherwise
28  mxberry.core.throwerror('wrongInput',...
29  'Unknown property: %s',prop{iProp});
30  end
31  end
32  %% check inputs
33  % check isEnabled
34  if ~(islogical(isEnabled)&&numel(isEnabled)==1)
35  mxberry.core.throwerror('wrongInput',...
36  'isEnabled must be scalar logical');
37  end
38  % check functionNameList
39  if ischar(functionNameList)
40  if isempty(functionNameList)||size(functionNameList,2)~=...
41  numel(functionNameList)
42  mxberry.core.throwerror('wrongInput',...
43  'functionNameList must be nonempty string');
44  end
45  functionNameList={functionNameList};
46  else
47  isnWrong=iscell(functionNameList);
48  if isnWrong
49  functionNameList=reshape(functionNameList,1,[]);
50  isnWrong=all(...
51  cellfun('isclass',functionNameList,'char')&...
52  cellfun('size',functionNameList,2)==...
53  cellfun('prodofsize',functionNameList)&...
54  ~cellfun('isempty',functionNameList));
55  end
56  if ~isnWrong
57  mxberry.core.throwerror('wrongInput',...
58  'functionNameList must be cell array with nonempty strings');
59  end
60  functionNameList=unique(functionNameList);
61  end
62  % check storageLocation
63  if isempty(storageLocation)||~(ischar(storageLocation)&&...
64  size(storageLocation,2)==numel(storageLocation))
65  mxberry.core.throwerror('wrongInput',...
66  'storageLocation must be nonempty string');
67  end
68  % check nMaxDatesOnDisk
69  isnWrong=isnumeric(nMaxDatesOnDisk)&&numel(nMaxDatesOnDisk)==1;
70  if isnWrong
71  nMaxDatesOnDisk=double(nMaxDatesOnDisk);
72  isnWrong=~isnan(nMaxDatesOnDisk)&&nMaxDatesOnDisk>=0&&...
73  floor(nMaxDatesOnDisk)==nMaxDatesOnDisk;
74  end
75  if ~isnWrong
76  mxberry.core.throwerror('wrongInput',...
77  'nMaxDatesOnDisk must be scalar nonnegative integer');
78  end
79  %% preprocess data storage
80  if ~mxberry.io.isdir(storageLocation)
81  mxberry.io.mkdir(storageLocation);
82  end
83  if isfinite(nMaxDatesOnDisk)&&isEnabled
84  % delete files that are more than nMaxDatesOnDisk dates on
85  % disk
86  SFileList=dir(storageLocation);
87  SFileList([SFileList.isdir])=[];
88  fileNameList={SFileList.name};
89  if ~isempty(fileNameList)
90  [~,fileNameList,extNameList]=cellfun(@fileparts,...
91  fileNameList,'UniformOutput',false);
92  isFileVec=strcmp(extNameList,'.mat');
93  if any(isFileVec)
94  fileNameList=fileNameList(isFileVec);
95  fileNameList=fileNameList(...
96  [SFileList(isFileVec).datenum]<=...
97  addtodate(floor(now),-nMaxDatesOnDisk,'day'));
98  nFiles=numel(fileNameList);
99  if nFiles
100  fileNameList=strcat(storageLocation,filesep,fileNameList,'.mat');
101  for iFile=1:nFiles
102  delete(fileNameList{iFile});
103  end
104  end
105  end
106  end
107  end
108  %% set properties
109  setMethodName=[className '.setPropInternal'];
110  feval(setMethodName,'isEnabled',isEnabled);
111  feval(setMethodName,'functionNameList',functionNameList);
112  feval(setMethodName,'prefixList',cell(1,0));
113  feval(setMethodName,'loggerObj',Logger.getLogger(className));
114  feval(setMethodName,'storageLocation',storageLocation);
115  feval(setMethodName,'filePostfix',mxberry.system.getpidhost());
116  end
117  %
118  function addPrefixToList(prefixStr)
119 
120  %% initial actions
121  className=mfilename('class');
122  if ~feval([className '.getIsEnabled'])
123  return;
124  end
125  if isempty(prefixStr)||~(...
126  ischar(prefixStr)&&size(prefixStr,2)==numel(prefixStr))
127  mxberry.core.throwerror('wrongInput',...
128  'prefixStr must be nonemtpy string');
129  end
130  %% add prefix
131  prefixList=feval([className '.getPropInternal'],'prefixList');
132  feval([className '.setPropInternal'],'prefixList',horzcat(prefixList,{prefixStr}));
133  end
134  %
135  function removePrefixFromList()
136 
137  %% initial actions
138  className=mfilename('class');
139  if ~feval([className '.getIsEnabled'])
140  return;
141  end
142  %% remove prefix
143  prefixList=feval([className '.getPropInternal'],'prefixList');
144  if isempty(prefixList)
145  mxberry.core.throwerror('wrongObjState',...
146  'addPrefixToList must be called before calling this method');
147  end
148  feval([className '.setPropInternal'],'prefixList',prefixList(1:end-1));
149  end
150  %
151  function log()
152 
153  className=mfilename('class');
154  if ~feval([className '.getIsEnabled'])
155  return;
156  end
157  [~,fullFuncName,isLogged]=feval([className '.getFunctionProps'],2);
158  if ~isLogged
159  return;
160  end
161  getMethodName=[className '.getPropInternal'];
162  loggerObj=feval(getMethodName,'loggerObj');
163  loggerObj.info([fullFuncName ' is performed']);
164  end
165  %
166  function logData()
167 
168  className=mfilename('class');
169  if ~feval([className '.getIsEnabled'])
170  return;
171  end
172  [shortFuncName,fullFuncName,isLogged]=feval([className '.getFunctionProps'],2);
173  if ~isLogged
174  return;
175  end
176  loggerObj=feval([className '.getPropInternal'],'loggerObj');
177  fileName=feval([className '.getDataFileName'],shortFuncName,fullFuncName);
178  [~,shortFileName]=fileparts(fileName);
179  loggerObj.info([fullFuncName ' is performed, data with local variables are in ' shortFileName]);
180  evalin('caller',['save(' fileName ')']);
181  end
182  %
183  function flush()
184 
185  className=mfilename('class');
186  feval([className '.flushInternal'],className);
187  end
188  end
189 
190  methods (Access=protected,Static)
191  function isEnabled=getIsEnabled()
192 
193  className=mfilename('class');
194  [isEnabled,isConfigured]=feval([className '.getPropInternal'],...
195  'isEnabled',true,className);
196  isEnabled=isConfigured&&~isempty(isEnabled)&&isEnabled;
197  end
198  %
199  function fileName=getDataFileName(shortFuncName,fullFuncName)
200 
201  className=mfilename('class');
202  getMethodName=[className '.getPropInternal'];
203  fileName=[feval(getMethodName,'storageLocation') filesep ...
204  shortFuncName '_' feval(getMethodName,'filePostfix') '_'...
205  datestr(now,30) '_' mxberry.core.hash(fullFuncName) '.mat'];
206  end
207  %
208  function [shortFuncName,fullFuncName,isLogged]=getFunctionProps(indStack)
209  import mxberry.core.cell.cell2tablestr;
210  curClassName=mfilename('class');
211  %% find function names (short and full one, but without
212  %% prefixes)
213  StFunc=dbstack('-completenames');
214  nFuncs=numel(StFunc);
215  isFound=false;
216  isCheck=nargin==0;
217  if isCheck
218  indStack=3;
219  else
220  indStack=indStack+1;
221  end
222  for iFunc=indStack:nFuncs
223  % determine name of class (if any) and name of
224  % method (function or script)
225  StFuncCur=StFunc(iFunc);
226  [pathStr,fileName]=fileparts(StFuncCur.file);
227  pathStr=strrep(pathStr,[filesep '+'],'.');
228  indClass=strfind(pathStr,[filesep '@']);
229  isClass=~isempty(indClass);
230  if isClass
231  pathStr(indClass)='.';
232  pathStr(indClass+1)=[];
233  end
234  curInd=find(pathStr==filesep,1,'last');
235  if ~isempty(curInd)
236  pathStr=pathStr(curInd+1:end);
237  end
238  curInd=find(pathStr=='.',1,'first');
239  if isempty(curInd)
240  isPath=false;
241  else
242  pathStr=pathStr(curInd+1:end);
243  isPath=~isempty(pathStr);
244  end
245  methodName=StFuncCur.name;
246  curInd=find(methodName=='.',1,'first');
247  if ~isempty(curInd)
248  methodName=methodName(curInd+1:end);
249  if ~isClass
250  pathStr=[pathStr '.' fileName]; %#ok<AGROW>
251  isClass=true;
252  end
253  end
254  shortFuncName=methodName(find(['/' methodName]=='/',1,'last'):end);
255  className='';
256  if isPath
257  if isClass
258  className=pathStr;
259  else
260  methodName=[pathStr '.' methodName]; %#ok<AGROW>
261  end
262  end
263  if isCheck
264  isFound=isempty(className);
265  if ~isFound
266  isFound=~any(strcmp(superclasses(className),curClassName));
267  end
268  else
269  isFound=true;
270  end
271  if isFound
272  fullFuncName=methodName;
273  if ~isempty(className)
274  fullFuncName=[className '.' fullFuncName]; %#ok<AGROW>
275  end
276  break;
277  end
278  end
279  if ~isFound
280  mxberry.core.throwerror('wrongCall',[...
281  'This method must be called from function, script or '...
282  'method of some class different from descendants of %s'],...
283  mfilename('class'));
284  end
285  %% process fullFuncName and isLogged
286  if nargout>1
287  getMethodName=[curClassName '.getPropInternal'];
288  prefixList=feval(getMethodName,'prefixList');
289  fullFuncName=cell2tablestr([],[prefixList {fullFuncName}],'.');
290  if nargout>2
291  isLogged=any(strcmp(fullFuncName,...
292  feval(getMethodName,'functionNameList')));
293  end
294  end
295  end
296  %
297  function [propVal,isThere]=getPropInternal(propName,isPresenceChecked,className)
298 
299  if nargin>=3
300  branchName=className;
301  else
302  branchName=mfilename('class');
303  end
304  if nargin<2
305  isPresenceChecked=false;
306  end
307  [propVal,isThere]=mxberry.core.obj.StaticPropStorage.getPropInternal(...
308  branchName,propName,isPresenceChecked);
309  end
310  %
311  function setPropInternal(propName,propVal,className)
312 
313  if nargin>=3
314  branchName=className;
315  else
316  branchName=mfilename('class');
317  end
319  branchName,propName,propVal);
320  end
321  end
322 end
function filesep()
static function setPropInternal(in branchName, in propName, in propVal)
function hash(in inpArr, in methodName)
OBJECTHASH counts the hash of input object/array.
function cell2tablestr(in titleList, in dataCell, in colSepSeq, in varargin)
CELL2TABLESTR - converts a cell array into a table-like char array (or a cell array of strings repres...
function unique(in inpVec)
UNIQUE for arrays of any type.
static function getPropInternal(in branchName, in propName, in isPresenceChecked)
function parseparams(in args, in propNameList, in nRegExpected, in nPropExpected)
PARSEPARAMS behaves exactly as a built-in Matlab function apart from the incorrect behavior of Matlab...