IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ticket #379: psTrace.c

File psTrace.c, 17.3 KB (added by eugene, 21 years ago)

psTrace.c with fixes for psTraceSetDestination, NULL tests

Line 
1/** @file psTrace.c
2 * \brief basic run-time trace facilities
3 * \ingroup LogTrace
4 *
5 * This file will hold the code for procedures to insert
6 * trace messages into the code.
7 *
8 * @author Robert Lupton, Princeton University
9 * @author GLG, MHPCC
10 *
11 * @version $Revision: 1.44 $ $Name: rel5_0 $
12 * @date $Date: 2005/03/29 21:31:54 $
13 *
14 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
15 */
16
17/*****************************************************************************
18 NOTES:
19 In the SRD, higher trace levels correspond to a numerically lower trace
20 value in the code. This is a bit confusing. For example, a high-level
21 message might be something like "Begin Processing". The module programmer
22 might give that a numerically low trace level, such as 1, so then any
23 non-zero trace level in that code component will display thatmessage.
24
25 We build a tree of trace components. Every node in the tree has a
26 depth, which is it's distance from the root. However, this is not
27 not the same thing as a node's "level", which corresponds to the
28 trace level of that node.
29
30I think the following is the correct behavior, but not sure:
31 PS_UNKNOWN_TRACE_LEVEL: We never set the level of a component to this
32 value. This value is only used when psTraceGetLevel is called with
33 a bad component name, or if the component root is undefined, I think.
34
35 PS_DEFAULT_TRACE_LEVEL: This should only be used when adding the
36 intermediate components of a psS64 name. Ie. the "B" in .A.B.C
37
38 *****************************************************************************/
39
40#ifndef PS_NO_TRACE
41
42#include <unistd.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <string.h>
46#include <stdarg.h>
47#include "psMemory.h"
48#include "psTrace.h"
49#include "psString.h"
50#include "psError.h"
51#include "psLogMsg.h"
52
53#include "psSysUtilsErrors.h"
54
55static p_psComponent* cRoot = NULL; // The root of the trace component
56static FILE *traceFP = NULL; // File destination for messages.
57
58static void componentFree(p_psComponent* comp);
59static p_psComponent* componentAlloc(const char *name, psS32 level);
60
61/*****************************************************************************
62componentAlloc(): allocate memory for a new node, and initialize members.
63 *****************************************************************************/
64static p_psComponent* componentAlloc(const char *name, psS32 level)
65{
66 p_psComponent* comp = psAlloc(sizeof(p_psComponent));
67
68 p_psMemSetPersistent(comp,true);
69 p_psMemSetDeallocator(comp, (psFreeFcn) componentFree);
70 comp->name = psStringCopy(name);
71 p_psMemSetPersistent((psPtr)comp->name,true);
72 comp->level = level;
73 comp->n = 0;
74 comp->p_psSpecified = false;
75 comp->subcomp = NULL;
76 return comp;
77}
78
79/*****************************************************************************
80componentFree(): free the current node in the root tree, and all children
81nodes as well.
82 *****************************************************************************/
83static void componentFree(p_psComponent* comp)
84{
85 if (comp == NULL) {
86 return;
87 }
88
89 if (comp->subcomp != NULL) {
90 for (psS32 i = 0; i < comp->n; i++) {
91 p_psMemSetPersistent(comp->subcomp[i],false);
92 psFree(comp->subcomp[i]);
93 }
94 p_psMemSetPersistent(comp->subcomp,false);
95 psFree(comp->subcomp);
96 }
97
98 p_psMemSetPersistent((psPtr)comp->name,false);
99 psFree((psPtr)comp->name);
100}
101
102/*****************************************************************************
103initTrace(): simply initialize the component root tree.
104*****************************************************************************/
105static void initTrace(void)
106{
107 if (cRoot == NULL) {
108 cRoot = componentAlloc(".", PS_DEFAULT_TRACE_LEVEL);
109 }
110}
111
112/*****************************************************************************
113Set all trace levels to zero.
114
115XXX: Currently, no function calls this routine.
116 *****************************************************************************/
117void p_psTraceReset(p_psComponent* currentNode)
118{
119 psS32 i = 0;
120
121 if (NULL == currentNode) {
122 return;
123 }
124
125 currentNode->level = 0;
126 for (i = 0; i < currentNode->n; i++) {
127 if (NULL == currentNode->subcomp[i]) {
128 psLogMsg("p_psTraceReset", PS_LOG_WARN,
129 PS_ERRORTEXT_psTrace_NULL_SUBCOMPONENT,
130 i, currentNode->name);
131 } else {
132 p_psTraceReset(currentNode->subcomp[i]);
133 }
134 }
135 return;
136}
137
138/*****************************************************************************
139Set all trace levels to zero.
140 *****************************************************************************/
141void psTraceReset()
142{
143 psFree(cRoot);
144 cRoot = NULL;
145}
146
147/*****************************************************************************
148componentAdd(): Adds the component named "addNodeName" to the root tree.
149 *****************************************************************************/
150static psBool componentAdd(const char *addNodeName, psS32 level)
151{
152 psS32 i = 0; // Loop index variable.
153 char name[strlen(addNodeName) + 1]; // buffer for writeable copy.
154 char *pname = name;
155 char *firstComponent = NULL; // first component of name
156 p_psComponent* currentNode = cRoot;
157 psS32 nodeExists = 0;
158
159 // XXX: Verify that this is the correct behavior.
160 if (strcmp("", addNodeName) == 0) {
161 psError(PS_ERR_BAD_PARAMETER_NULL,true,
162 PS_ERRORTEXT_psTrace_ADD_NULL_COMPONENT);
163 return false;
164 }
165
166 // Is this the root node? If so, simply set level and return.
167 if (strcmp(".", addNodeName) == 0) {
168 cRoot->level = level;
169 return true;
170 }
171
172 if (addNodeName[0] != '.') {
173 psError(PS_ERR_BAD_PARAMETER_VALUE,true,
174 PS_ERRORTEXT_psTrace_MALFORMED_COMPONENT_NAME,
175 addNodeName);
176 return false;
177 }
178
179 strcpy(name, addNodeName);
180 pname = name+1;
181 // Iterate through the components of addNodeName. Strip off the first
182 // component of the name, find that in the root tree, or add it if it
183 // does not exist, then move to the next component in the name.
184
185 while (pname != NULL) {
186 firstComponent = pname;
187 pname = strchr(firstComponent, '.');
188 if (pname != NULL) {
189 *pname = '\0';
190 pname++;
191 }
192 nodeExists = 0;
193 for (i = 0; i < currentNode->n; i++) {
194 if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
195 currentNode = currentNode->subcomp[i];
196 nodeExists = 1;
197 if (pname == NULL) {
198 currentNode->level = level;
199 }
200 }
201 }
202
203 if (nodeExists == 0) {
204 currentNode->subcomp = psRealloc(currentNode->subcomp,
205 (currentNode->n + 1) * sizeof(p_psComponent* ));
206 p_psMemSetPersistent(currentNode->subcomp,true);
207
208 currentNode->n = (currentNode->n) + 1;
209
210 if (pname == NULL) {
211 // This is the final component to add.
212 currentNode->subcomp[(currentNode->n) - 1] = componentAlloc(firstComponent, level);
213 } else {
214 // We are adding an intermediate component. The trace level
215 // is not defined. An undefined trace level inherits the
216 // trace level of it's parent. However, we do not set that
217 // specifically here since that would inheritance to be a
218 // static, one-time, type of behavior.
219
220 currentNode->subcomp[(currentNode->n) - 1] = componentAlloc(firstComponent, PS_DEFAULT_TRACE_LEVEL);
221 }
222 currentNode = currentNode->subcomp[(currentNode->n) - 1];
223 }
224 }
225
226 return true;
227}
228
229/*****************************************************************************
230 psSetTraceLevel(): add the component named "comp" to the component tree,
231 if it is not already there, and set it's trace level to "level".
232
233 NOTE: We modified this so that the user may omit the leading "," in a
234 component name. Since the code was already implemented assuming the "."
235 was required, rather than change all that code, in this function, I
236 simply add a leading "." to the component name if there is none.
237
238 Input:
239 comp
240 level
241 Output:
242 none
243 Returns:
244 zero
245*****************************************************************************/
246psBool psTraceSetLevel(const char *comp, // component of interest
247 psS32 level) // desired trace level
248{
249 char *compName = NULL;
250
251 // If the root component tree does not exist, then initialize it.
252 if (cRoot == NULL) {
253 initTrace();
254 }
255
256 if (traceFP == NULL) {
257 traceFP = stderr;
258 }
259
260 // If the component name has no leading dot, then supply it.
261 if (comp[0] != '.') {
262 compName = (char *) psAlloc(10 + strlen(comp));
263 strcpy(compName, ".");
264 compName = strcat(compName, comp);
265 } else {
266 compName = (char *) comp;
267 }
268
269 // Add the new component to the component tree.
270 if ( !componentAdd(compName, level) ) {
271 psError(PS_ERR_UNKNOWN, false,
272 PS_ERRORTEXT_psTrace_FAILED_TO_ADD_COMPONENT,
273 level,
274 compName);
275
276 if (comp[0] != '.') {
277 psFree(compName);
278 }
279 return false;
280 }
281
282 if (comp[0] != '.') {
283 psFree(compName);
284 }
285
286 return true;
287}
288
289/*****************************************************************************
290 doGetTraceLevel()
291 This function recursively searches the root component tree for the
292 component named "name", which is supplied by a parameter. If it
293 finds that component, it returns the level of that component.
294 Otherwise, it returns ???.
295
296 NOTE: We modified this so that the user may omit the leading "," in a
297 component name. Since the code was already implemented assuming the "."
298 was required, rather than change all that code, in this function, I
299 simply add a leading "." to the component name if there is none.
300
301 Inputs:
302 name:
303 Outputs:
304 none
305 Returns:
306 The trace level of the "name" component.
307 *****************************************************************************/
308static psS32 doGetTraceLevel(const char *aname)
309{
310 char name[strlen(aname) + 1]; // need a writeable copy: for strsep()
311 char *pname = name;
312 char *firstComponent = NULL; // first component of name
313 p_psComponent* currentNode = cRoot;
314 psS32 i = 0;
315 psS32 defaultLevel = 0;
316
317 if (NULL == currentNode) {
318 return (PS_UNKNOWN_TRACE_LEVEL);
319 }
320
321 if (strcmp(".", aname) == 0) {
322 return (cRoot->level);
323 }
324
325 if (aname[0] != '.') {
326 return (PS_UNKNOWN_TRACE_LEVEL);
327 }
328
329 defaultLevel = cRoot->level;
330 strcpy(name, aname);
331 pname = name+1;
332 while (pname != NULL) {
333 firstComponent = pname;
334 pname = strchr(firstComponent, '.');
335 if (pname != NULL) {
336 *pname = '\0';
337 pname++;
338 }
339 for (i = 0; i < currentNode->n; i++) {
340 if (NULL == currentNode->subcomp[i]) {
341 psLogMsg("p_psTraceReset", PS_LOG_WARN,
342 PS_ERRORTEXT_psTrace_NULL_SUBCOMPONENT,
343 i, currentNode->name);
344 }
345
346 if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
347 currentNode = currentNode->subcomp[i];
348 // For level inheritance purpose, we save the level of this
349 // component if it is not DEFAULT.
350 if (currentNode->level != PS_DEFAULT_TRACE_LEVEL) {
351 defaultLevel = currentNode->level;
352 }
353 // Determine if this is the last component:
354 if (pname == NULL) {
355 if (currentNode->level != PS_DEFAULT_TRACE_LEVEL) {
356 return (currentNode->level);
357 } else {
358 return(defaultLevel);
359 }
360 }
361 }
362 }
363 }
364 return(defaultLevel);
365}
366
367/*****************************************************************************
368 psTraceLevelGet()
369 Return a trace level of "name" in the root component tree. If the
370 exact string of components in "name" does not exist in the root
371 tree, we return the deepest level of the match.
372 Input:
373 name
374 Output:
375 none
376 Return:
377 The level of "name" in the root component tree.
378 *****************************************************************************/
379psS32 psTraceGetLevel(const char *name)
380{
381 char *compName = NULL;
382 psS32 traceLevel;
383
384 if (cRoot == NULL) {
385 return (PS_UNKNOWN_TRACE_LEVEL);
386 }
387
388 // If the component name has no leading dot, then supply it.
389 if (name[0] != '.') {
390 compName = (char *) psAlloc(10 + strlen(name));
391 strcpy(compName, ".");
392 compName = strcat(compName, name);
393 traceLevel = doGetTraceLevel(compName);
394 psFree(compName);
395 } else {
396 // Search the component root tree, determine the trace level.
397 traceLevel = doGetTraceLevel(name);
398 }
399
400 // XXX: The default trace level is currently set at -1, which is not a
401 // valid trace level. This is convenient in determining whether or not
402 // a component should inherit the trace level from parent nodes. However,
403 // it's not clear that -1 should ever be returned by this function.
404 // The SDR is unclear on this point and we should probably request IfA
405 // comment.
406 if (traceLevel == PS_DEFAULT_TRACE_LEVEL) {
407 traceLevel = PS_THE_OTHER_DEFAULT_TRACE_LEVEL;
408 }
409
410 return(traceLevel);
411}
412
413/*****************************************************************************
414 doPrintTraceLevels()
415 This function recursively searches the component tree supplied by the
416 parameter "comp" and prints the name and level of each component.
417 Inputs:
418 comp: a node in the component tree.
419 level: the level of that node
420 Outputs:
421 none
422 Returns:
423 null
424 *****************************************************************************/
425static void doPrintTraceLevels(const p_psComponent* comp,
426 psS32 depth,
427 psS32 defLevel)
428{
429 psS32 i = 0;
430
431 if (traceFP == NULL) {
432 traceFP = stderr;
433 }
434
435 if (comp->name[0] == '\0') {
436 return;
437 } else {
438 if (comp->level == PS_DEFAULT_TRACE_LEVEL) {
439 fprintf(traceFP,"%*s%-*s %d\n", depth, "", 20 - depth, comp->name, defLevel);
440 } else {
441 fprintf(traceFP, "%*s%-*s %d\n", depth, "", 20 - depth, comp->name, comp->level);
442 }
443 }
444
445 for (i = 0; i < comp->n; i++) {
446 if (comp->level == PS_DEFAULT_TRACE_LEVEL) {
447 doPrintTraceLevels(comp->subcomp[i], depth + 1, defLevel);
448 } else {
449 doPrintTraceLevels(comp->subcomp[i], depth + 1, comp->level);
450 }
451 }
452}
453
454
455/*****************************************************************************
456psPrintTraceLevels(): Simply print all the trace levels in the trace level
457component tree.
458Inputs:
459 none
460Outputs:
461 none
462Returns:
463 null
464*****************************************************************************/
465void psTracePrintLevels(void)
466{
467 if (cRoot == NULL) {
468 return;
469 }
470
471 doPrintTraceLevels(cRoot, 0, PS_THE_OTHER_DEFAULT_TRACE_LEVEL);
472}
473
474/*****************************************************************************
475p_psTrace(): we display the trace message to standard output if the trace
476level of that message, supplied by the parameter "level" is higher than the
477trace level that is currently associated with the component named by the
478parameter "comp".
479Input:
480 comp
481 level
482 ... a printf-style output string.
483Output:
484 none
485Return:
486 null
487 *****************************************************************************/
488void p_psTrace(const char *comp, // component being traced
489 psS32 level, // desired trace level
490 ...) // arguments
491{
492 char *fmt = NULL;
493 va_list ap;
494 psS32 i = 0;
495
496 if (traceFP == NULL) {
497 traceFP = stderr;
498 }
499
500 if (NULL == comp) {
501 psError(PS_ERR_BAD_PARAMETER_NULL, true,
502 PS_ERRORTEXT_psTrace_NULL_TRACETREE,
503 __func__);
504 return;
505 }
506 // Only display this message if it's trace level is less than the level
507 // of it's associatedcomponent.
508 if (level <= psTraceGetLevel(comp)) {
509 va_start(ap, level);
510
511 // The following functions get the variable list of parameters with
512 // which this function was called, and print them to the standard
513 // output.
514 fmt = va_arg(ap, char *);
515
516 // We indent each message one space for each level of the message.
517 for (i = 0; i < level; i++) {
518 fprintf(traceFP, " ");
519 }
520 vfprintf(traceFP, fmt, ap);
521 va_end(ap);
522 }
523}
524
525// XXX EAM : I've added code to close the old traceFP (safely)
526void psTraceSetDestination(FILE * fp)
527{
528
529 bool special;
530
531 // XXX EAM perhaps return an error?
532 if (fp == NULL) {
533 return;
534 }
535
536 // cannot close traceFP if one of the special FILE ptrs
537 special = (traceFP == NULL);
538 special |= (traceFP == stdin);
539 special |= (traceFP == stdout);
540 special |= (traceFP == stderr);
541
542 if (!special) {
543 fclose (traceFP);
544 }
545 traceFP = fp;
546}
547
548FILE *psTraceGetDestination()
549{
550 if (traceFP == NULL) {
551 traceFP = stderr;
552 }
553 return traceFP;
554}
555
556#endif