1 /*
2 * log.c - logging module of websh 3
3 * nca-073-9
4 *
5 * Copyright (c) 1996-2000 by Netcetera AG.
6 * Copyright (c) 2001 by Apache Software Foundation.
7 * All rights reserved.
8 *
9 * See the file "license.terms" for information on usage and
10 * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * @(#) $Id: log.c 814683 2009-09-14 15:11:40Z ronnie $
13 *
14 */
15
16 #include "log.h"
17 #include "logtochannel.h"
18 #include "logtocmd.h"
19 #include "logtofile.h"
20 #include "logtosyslog.h"
21 #include "tcl.h"
22 #include <stdio.h>
23
24
25 /* ----------------------------------------------------------------------------
26 * Init --
27 * entry point for module weblog of websh3
28 * ------------------------------------------------------------------------- */
log_Init(Tcl_Interp * interp)29 int DLLEXPORT log_Init(Tcl_Interp * interp)
30 {
31
32 LogData *logData = NULL;
33 LogPlugIn *logtofile = NULL;
34 LogPlugIn *logtochannel = NULL;
35 LogPlugIn *logtocmd = NULL;
36 LogPlugIn *logtosyslog = NULL;
37
38 /* --------------------------------------------------------------------------
39 * interpreter running ?
40 * ----------------------------------------------------------------------- */
41 if (interp == NULL)
42 return TCL_ERROR;
43
44 /* --------------------------------------------------------------------------
45 * init internal data, and register with interp
46 * ----------------------------------------------------------------------- */
47 logData = createLogData();
48 WebAssertData(interp, logData, "log", TCL_ERROR);
49
50 /* --------------------------------------------------------------------------
51 * register data with interp
52 * ----------------------------------------------------------------------- */
53 Tcl_SetAssocData(interp, WEB_LOG_ASSOC_DATA,
54 destroyLogData, (ClientData) logData);
55
56 /* --------------------------------------------------------------------------
57 * register commands
58 * ----------------------------------------------------------------------- */
59 Tcl_CreateObjCommand(interp, "web::log",
60 Web_Log,
61 (ClientData) logData, (Tcl_CmdDeleteProc *) NULL);
62
63 Tcl_CreateObjCommand(interp, "web::loglevel",
64 Web_LogFilter,
65 (ClientData) logData, (Tcl_CmdDeleteProc *) NULL);
66
67 /* for compatibility with Websh 3.5 and earlier*/
68 Tcl_CreateObjCommand(interp, "web::logfilter",
69 Web_LogFilter,
70 (ClientData) logData, (Tcl_CmdDeleteProc *) NULL);
71
72 Tcl_CreateObjCommand(interp, "web::logdest",
73 Web_LogDest,
74 (ClientData) logData, (Tcl_CmdDeleteProc *) NULL);
75
76 /* --------------------------------------------------------------------------
77 * register log handler "channel"
78 * ----------------------------------------------------------------------- */
79 logtochannel = createLogPlugIn();
80 WebAssertData(interp, logtochannel, "log_Init/logtochannel plugin",
81 TCL_ERROR)
82
83 logtochannel->constructor = createLogToChannel;
84 logtochannel->destructor = destroyLogToChannel;
85 logtochannel->handler = logToChannel;
86
87 registerLogPlugIn(interp, "channel", logtochannel);
88
89 /* --------------------------------------------------------------------------
90 * register log handler "file"
91 * ----------------------------------------------------------------------- */
92 logtofile = createLogPlugIn();
93 WebAssertData(interp, logtofile, "log_Init/logtofile plugin", TCL_ERROR)
94
95 logtofile->constructor = createLogToFile;
96 logtofile->destructor = destroyLogToFile;
97 logtofile->handler = logToFile;
98
99 registerLogPlugIn(interp, "file", logtofile);
100
101 /* --------------------------------------------------------------------------
102 * register log handler "command"
103 * ----------------------------------------------------------------------- */
104 logtocmd = createLogPlugIn();
105 WebAssertData(interp, logtocmd, "log_Init/logtocmd plugin", TCL_ERROR)
106
107 logtocmd->constructor = createLogToCmd;
108 logtocmd->destructor = destroyLogToCmd;
109 logtocmd->handler = logToCmd;
110
111 registerLogPlugIn(interp, "command", logtocmd);
112
113 /* --------------------------------------------------------------------------
114 * register log handler "syslog"
115 * ----------------------------------------------------------------------- */
116 #ifndef WIN32
117 logtosyslog = createLogPlugIn();
118 WebAssertData(interp, logtocmd, "log_Init/logtosyslog plugin", TCL_ERROR)
119
120 logtosyslog->constructor = createLogToSyslog;
121 logtosyslog->destructor = destroyLogToSyslog;
122 logtosyslog->handler = logToSyslog;
123
124 registerLogPlugIn(interp, "syslog", logtosyslog);
125 #endif
126 /* --------------------------------------------------------------------------
127 * done
128 * ----------------------------------------------------------------------- */
129 return TCL_OK;
130 }
131
132 /* ----------------------------------------------------------------------------
133 * createLogData --
134 * ------------------------------------------------------------------------- */
createLogData()135 LogData *createLogData()
136 {
137
138 LogData *logData = NULL;
139
140 logData = WebAllocInternalData(LogData);
141
142 if (logData != NULL) {
143
144 /* initialize list of destination and levels */
145 logData->listOfFilters = NULL;
146 logData->filterSize = 0;
147 logData->listOfDests = NULL;
148 logData->destSize = 0;
149 /* fake calls to initialize filters and destinations */
150 insertIntoFilterList(logData, (LogLevel *) NULL);
151 insertIntoDestList(logData, (LogDest *) NULL);
152
153 HashUtlAllocInit(logData->listOfPlugIns, TCL_STRING_KEYS);
154 logData->logSubst = LOG_SUBSTDEFAULT;
155 logData->safeLog = LOG_SAFEDEFAULT;
156 logData->keep = 0;
157 }
158
159 return logData;
160 }
161
162 /* ----------------------------------------------------------------------------
163 * destroyLogData --
164 * ------------------------------------------------------------------------- */
destroyLogData(ClientData clientData,Tcl_Interp * interp)165 void destroyLogData(ClientData clientData, Tcl_Interp * interp)
166 {
167
168 LogData *logData = NULL;
169
170 if (clientData != NULL) {
171
172 logData = (LogData *) clientData;
173
174 /* ..................................................................... */
175 if (logData->listOfFilters != NULL) {
176
177 int i;
178 LogLevel ** logLevels = logData->listOfFilters;
179 for (i = 0; i < logData->filterSize; i++) {
180 if (logLevels[i] != NULL) {
181 destroyLogLevel(logLevels[i], interp);
182 }
183 }
184 WebFreeIfNotNull(logData->listOfFilters);
185 logData->filterSize = 0;
186 }
187
188 /* ................................................................ */
189 if (logData->listOfDests != NULL) {
190
191 int i;
192 LogDest ** logDests = logData->listOfDests;
193 for (i = 0; i < logData->destSize; i++) {
194 if (logDests[i] != NULL) {
195 destroyLogDest(logDests[i], interp);
196 }
197 }
198 WebFreeIfNotNull(logData->listOfDests);
199 logData->destSize = 0;
200 }
201
202
203 /* ................................................................ */
204 if (logData->listOfPlugIns != NULL) {
205
206 resetHashTableWithContent(logData->listOfPlugIns, TCL_STRING_KEYS,
207 destroyLogPlugIn, interp);
208
209 HashUtlDelFree(logData->listOfPlugIns);
210 logData->listOfPlugIns = NULL;
211 }
212
213 WebFreeIfNotNull(logData);
214 }
215 }
216
217
218 /* ----------------------------------------------------------------------------
219 * createLogLevel -- allocate memory for a new LogLevel, and set content
220 * facility -> like "websh3"
221 * min -> alert | error | warning | info | debug
222 * max -> as min
223 * cnt -> if 0 <= cnt <= 2^15, use cnt for name of filter
224 * otherwise: don't set name (as for web::log)
225 * ------------------------------------------------------------------------- */
createLogLevel()226 LogLevel *createLogLevel()
227 {
228
229 LogLevel *logLevel = NULL;
230
231 logLevel = WebAllocInternalData(LogLevel);
232 if (logLevel != NULL) {
233
234 logLevel->keep = 0;
235 logLevel->facility = NULL;
236 logLevel->minSeverity = -1;
237 logLevel->maxSeverity = -1;
238 }
239
240 return logLevel;
241 }
242
243 /* ----------------------------------------------------------------------------
244 * destroyLogLevel -- free memory for LogLevel
245 * ------------------------------------------------------------------------- */
destroyLogLevel(void * level,void * dum)246 int destroyLogLevel(void *level, void *dum)
247 {
248
249 LogLevel *logLevel = NULL;
250
251 if (level != NULL) {
252
253 logLevel = (LogLevel *) level;
254
255 WebFreeIfNotNull(logLevel->facility);
256 WebFreeIfNotNull(logLevel);
257 }
258 return TCL_OK;
259 }
260
261 /* ----------------------------------------------------------------------------
262 * createLogName --
263 * ------------------------------------------------------------------------- */
createLogName(char * prefix,int cnt)264 char *createLogName(char *prefix, int cnt)
265 {
266
267 char str[64]; /* more than enough space for logDest%d */
268 char *name;
269
270 if (prefix == NULL)
271 return NULL;
272 if (strlen(prefix) > 10)
273 return NULL;
274
275 if ((cnt >= 0) && (cnt < (1 << 15))) {
276 sprintf(str, "%s%d", prefix, cnt);
277 name = allocAndSet(str);
278 } else {
279 name = NULL;
280 }
281
282 return name;
283 }
284
285 /* ----------------------------------------------------------------------------
286 * getIndextFromLogName --
287 * ------------------------------------------------------------------------- */
getIndexFromLogName(char * format,char * string)288 int getIndexFromLogName(char *format, char *string) {
289 int i = -1;
290 int index = -1;
291 if (sscanf(string, format, &index) == 1) {
292 i = index;
293 }
294 return i;
295 }
296
297 /* ----------------------------------------------------------------------------
298 * insertIntoDestList --
299 * ------------------------------------------------------------------------- */
insertIntoDestList(LogData * logData,LogDest * logDest)300 char * insertIntoDestList(LogData *logData, LogDest *logDest) {
301 int i;
302 LogDest ** logDests = logData->listOfDests;
303 for (i = 0; i < logData->destSize; i++) {
304 if (logDests[i] == NULL) {
305 if (logDest == NULL)
306 return NULL;
307 logDests[i] = logDest;
308 return createLogName(LOG_DEST_PREFIX, i);
309 }
310 }
311 {
312 /* list too small: increase size */
313 LogDest ** newLogDests = (LogDest **) Tcl_Alloc((LOG_LIST_INITIAL_SIZE + logData->destSize) * sizeof(LogDest *));
314 if (newLogDests == NULL) {return NULL;}
315 /* copy old list to new list */
316 memcpy(newLogDests, logDests, logData->destSize * sizeof(LogDest *));
317 /* init new entries to NULL */
318 for (i = 0; i < LOG_LIST_INITIAL_SIZE; i++) {
319 newLogDests[i + logData->destSize] = NULL;
320 }
321 logData->listOfDests = newLogDests;
322 logData->destSize += LOG_LIST_INITIAL_SIZE;
323 WebFreeIfNotNull(logDests);
324 if (logDest != NULL) {
325 /* only when not fake call to inizialize listOfDests*/
326 return insertIntoDestList(logData, logDest);
327 } else {
328 return NULL;
329 }
330 }
331 }
332
333 /* ----------------------------------------------------------------------------
334 * insertIntoFilterList --
335 * ------------------------------------------------------------------------- */
insertIntoFilterList(LogData * logData,LogLevel * logLevel)336 char * insertIntoFilterList(LogData *logData, LogLevel *logLevel) {
337 int i;
338 LogLevel ** logLevels = logData->listOfFilters;
339 for (i = 0; i < logData->filterSize; i++) {
340 if (logLevels[i] == NULL) {
341 if (logLevel == NULL)
342 return NULL;
343 logLevels[i] = logLevel;
344 return createLogName(LOG_FILTER_PREFIX, i);
345 }
346 }
347 {
348 /* list too small: increase size */
349 LogLevel ** newLogLevels = (LogLevel **) Tcl_Alloc((LOG_LIST_INITIAL_SIZE + logData->filterSize) * sizeof(LogLevel *));
350 if (newLogLevels == NULL) {return NULL;}
351 /* copy old list to new list */
352 memcpy(newLogLevels, logLevels, logData->filterSize * sizeof(LogLevel *));
353 /* init new entries to NULL */
354 for (i = 0; i < LOG_LIST_INITIAL_SIZE; i++) {
355 newLogLevels[i + logData->filterSize] = NULL;
356 }
357 logData->listOfFilters = newLogLevels;
358 logData->filterSize += LOG_LIST_INITIAL_SIZE;
359 WebFreeIfNotNull(logLevels);
360 if (logLevel != NULL) {
361 /* only when not fake call to inizialize listOfDests*/
362 return insertIntoFilterList(logData, logLevel);
363 } else {
364 return NULL;
365 }
366 }
367 }
368
369 /* ----------------------------------------------------------------------------
370 * createLogDest --
371 * ------------------------------------------------------------------------- */
createLogDest()372 LogDest *createLogDest()
373 {
374
375 LogDest *logDest = NULL;
376
377 logDest = WebAllocInternalData(LogDest);
378
379 logDest->keep = 0;
380 logDest->format = NULL;
381 logDest->maxCharInMsg = -1; /* Tcl_Append... --> -1 is all chars */
382 logDest->plugIn = NULL;
383 logDest->plugInData = NULL;
384
385 return logDest;
386 }
387
388 /* ----------------------------------------------------------------------------
389 * destroyLogDest --
390 * ------------------------------------------------------------------------- */
destroyLogDest(void * dest,void * env)391 int destroyLogDest(void *dest, void *env)
392 {
393
394 Tcl_Interp *interp = NULL;
395 LogDest *logDest = NULL;
396
397 if ((dest == NULL) || (env == NULL))
398 return TCL_ERROR;
399
400 logDest = (LogDest *) dest;
401 interp = (Tcl_Interp *) env;
402
403 /* ------------------------------------------------------------------------
404 * get rid of any data
405 * --------------------------------------------------------------------- */
406 if ((logDest->plugIn != NULL) && (logDest->plugInData != NULL)) {
407
408 /* --------------------------------------------------------------------
409 * call destructor
410 * ----------------------------------------------------------------- */
411 logDest->plugIn->destructor(interp, logDest->plugInData);
412 }
413
414 /* ------------------------------------------------------------------------
415 * unlink plugIn from logDest. Keep plugIn alive, though.
416 * --------------------------------------------------------------------- */
417 logDest->plugIn = NULL;
418
419 if (logDest->filter != NULL)
420 destroyLogLevel(logDest->filter, NULL);
421
422 /* ------------------------------------------------------------------------
423 * free rest items in struct, if needed
424 * --------------------------------------------------------------------- */
425 WebFreeIfNotNull(logDest->format);
426
427 WebFreeIfNotNull(logDest);
428
429 return TCL_OK;
430 }
431
432
433
434 /* ----------------------------------------------------------------------------
435 * Web_Log -- distribute a log message
436 * ------------------------------------------------------------------------- */
Web_Log(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])437 int Web_Log(ClientData clientData,
438 Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[])
439 {
440
441 LogData *logData;
442
443 /* ------------------------------------------------------------------------
444 * check for internal data
445 * --------------------------------------------------------------------- */
446 WebAssertData(interp, clientData, "Web_Log", TCL_ERROR);
447 logData = (LogData *) clientData;
448
449 /* ------------------------------------------------------------------------
450 * try to be fast
451 * --------------------------------------------------------------------- */
452 if (objc == 3) {
453 return logImpl(interp, logData, Tcl_GetString(objv[1]), objv[2]);
454 }
455
456 /* ------------------------------------------------------------------------
457 * wrong args
458 * --------------------------------------------------------------------- */
459 Tcl_WrongNumArgs(interp, 1, objv, "level message");
460 return TCL_ERROR;
461 }
462
463
464 /* ----------------------------------------------------------------------------
465 * Web_LogDest -- manage list of dests
466 * ------------------------------------------------------------------------- */
Web_LogDest(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])467 int Web_LogDest(ClientData clientData,
468 Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[])
469 {
470
471 LogData *logData = NULL;
472 int idx;
473 int iCurArg;
474
475 static TCLCONST char *params[] = { "-maxchar",
476 "-format",
477 NULL
478 };
479 enum params
480 { MAXCHAR, FORMAT };
481 static TCLCONST char *subCommands[] = {
482 WEB_LOG_SUBCMD_ADD,
483 WEB_LOG_SUBCMD_DELETE,
484 WEB_LOG_SUBCMD_NAMES,
485 WEB_LOG_SUBCMD_LEVELS,
486 NULL
487 };
488 enum subCommands
489 { ADD, DELETE, NAMES, LEVELS };
490
491 /* --------------------------------------------------------------------------
492 * check for internal data
493 * ----------------------------------------------------------------------- */
494 WebAssertData(interp, clientData, "Web_LogDest", TCL_ERROR)
495 logData = (LogData *) clientData;
496
497 /* --------------------------------------------------------------------------
498 * check arguments
499 * ----------------------------------------------------------------------- */
500 if (objc < 2) {
501 Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
502 return TCL_ERROR;
503 }
504
505 /* --------------------------------------------------------------------------
506 * scan for options
507 * ----------------------------------------------------------------------- */
508 if (Tcl_GetIndexFromObj(interp, objv[1], subCommands, "option", 0, &idx)
509 != TCL_OK)
510 return TCL_ERROR;
511
512 /* --------------------------------------------------------------------------
513 * switch on subcommand
514 * ----------------------------------------------------------------------- */
515
516 switch ((enum subCommands) idx) {
517
518 case ADD:{
519
520 /* ------------------------------------------------------------------------
521 * ok, add sytnax is as follows:
522 * web::logdest add [-format bla -maxchar 100] level {type specific stuff}
523 * 0 1 2 j j+1
524 * --------------------------------------------------------------------- */
525
526 char *name = NULL;
527 char *format = NULL;
528 LogLevel *logLevel = NULL;
529 LogPlugIn *logPlugIn = NULL;
530 ClientData logPlugInData = NULL;
531 LogDest *logDest = NULL;
532 Tcl_Obj *tcloTmp;
533 long maxCharInMsg = -1;
534 int iUnknown = 0;
535
536 /* argdbg(objc,objv,stdout); */
537
538 iCurArg =
539 argIndexOfFirstArg(objc - 1, &(objv[1]), params, NULL) + 1;
540
541 /* check for known options */
542 iUnknown =
543 argHasOnlyAccepted(objc - 1, &(objv[1]), params, iCurArg - 1);
544 if (iUnknown > 0) {
545 /* let Tcl format the error message */
546 Tcl_GetIndexFromObj(interp, objv[iUnknown + 1], params,
547 "option", 0, &idx);
548 return TCL_ERROR;
549 }
550
551 /* check for -format */
552 if ((tcloTmp = argValueOfKey(objc, objv, (char *)params[FORMAT])) != NULL) {
553 format = allocAndSet(Tcl_GetString(tcloTmp));
554 }
555 else {
556 format = allocAndSet(WEB_LOG_DEFAULTFORMAT);
557 }
558
559 /* check for -maxchar */
560 if ((tcloTmp =
561 argValueOfKey(objc, objv, (char *)params[MAXCHAR])) != NULL) {
562 if (Tcl_GetLongFromObj(interp, tcloTmp, &maxCharInMsg) ==
563 TCL_ERROR) {
564 LOG_MSG(interp, WRITE_LOG | SET_RESULT, __FILE__,
565 __LINE__, "web::logdest", WEBLOG_INFO,
566 "cannot read long from -maxchar \"",
567 Tcl_GetString(tcloTmp), "\"", NULL);
568 return TCL_ERROR;
569 }
570 }
571
572 /* ------------------------------------------------------------------------
573 * now iCurArg is level, iCurArg+1 is type, (+2 is type specific)
574 * --------------------------------------------------------------------- */
575 if ((iCurArg + 1) >= objc) {
576 Tcl_WrongNumArgs(interp, 1, objv, WEB_LOG_USAGE_LOGDEST_ADD);
577 WebFreeIfNotNull(format);
578 return TCL_ERROR;
579 }
580
581 /* ------------------------------------------------------------------------
582 * get handler for type
583 * --------------------------------------------------------------------- */
584 logPlugIn = (LogPlugIn *) getFromHashTable(logData->listOfPlugIns,
585 Tcl_GetString(objv
586 [iCurArg
587 + 1]));
588 if (logPlugIn == NULL) {
589 Tcl_SetResult(interp, "no log handler of type \"", NULL);
590 Tcl_AppendResult(interp, Tcl_GetString(objv[iCurArg + 1]),
591 "\" registered", NULL);
592 WebFreeIfNotNull(format);
593 return TCL_ERROR;
594 }
595
596 /* ------------------------------------------------------------------------
597 * parse level
598 * --------------------------------------------------------------------- */
599 logLevel =
600 parseLogLevel(interp, Tcl_GetString(objv[iCurArg]), "user",
601 -1);
602 if (logLevel == NULL) {
603 WebFreeIfNotNull(format);
604 return TCL_ERROR;
605 }
606
607 /* ------------------------------------------------------------------------
608 * call constructor
609 * --------------------------------------------------------------------- */
610 if ((logPlugInData =
611 logPlugIn->constructor(interp,
612 clientData, objc - (iCurArg + 1),
613 &(objv[iCurArg + 1]))) == NULL) {
614 destroyLogLevel(logLevel, NULL);
615 WebFreeIfNotNull(name);
616 WebFreeIfNotNull(format);
617 return TCL_ERROR;
618 }
619
620 /* ------------------------------------------------------------------------
621 * ok, make the logDest
622 * --------------------------------------------------------------------- */
623 logDest = createLogDest();
624 if (logDest == NULL) {
625 Tcl_SetResult(interp, "cannot create log destination", NULL);
626 destroyLogLevel(logLevel, NULL);
627 WebFreeIfNotNull(name);
628 WebFreeIfNotNull(format);
629 return TCL_ERROR;
630 }
631 logDest->filter = logLevel;
632 logDest->format = format;
633 logDest->plugIn = logPlugIn;
634 logDest->plugInData = logPlugInData;
635 logDest->maxCharInMsg = maxCharInMsg;
636 logDest->keep = logData->keep;
637
638 /* ----------------------------------------------------------
639 * and add to list
640 * ---------------------------------------------------------- */
641
642 name = insertIntoDestList(logData, logDest);
643 if (name == NULL) {
644 Tcl_SetResult(interp, "cannot append new log destination to list", NULL);
645 destroyLogDest(logDest, interp);
646 destroyLogLevel(logLevel, NULL);
647 WebFreeIfNotNull(format);
648 return TCL_ERROR;
649 }
650 Tcl_SetResult(interp, name, Tcl_Free);
651 return TCL_OK;
652 }
653 case NAMES:{
654
655 Tcl_ResetResult(interp);
656
657 if (logData->listOfDests != NULL) {
658 int i;
659 LogDest ** logDests = logData->listOfDests;
660 for (i = 0; i < logData->destSize; i++) {
661 if (logDests[i] != NULL) {
662 char *name = createLogName(LOG_DEST_PREFIX, i);
663 if (name != NULL) {
664 Tcl_AppendElement(interp, name);
665 Tcl_Free(name);
666 }
667 }
668 }
669 }
670 return TCL_OK;
671 }
672 case LEVELS:{
673
674 int namesIsFirst = TCL_OK;
675 LogDest *logDest = NULL;
676
677 Tcl_SetResult(interp, "", NULL);
678
679 if (logData->listOfDests != NULL) {
680
681 int i;
682 LogDest ** logDests = logData->listOfDests;
683 for (i = 0; i < logData->destSize; i++) {
684 if (logDests[i] != NULL) {
685 char * name = createLogName(LOG_DEST_PREFIX, i);
686 if (namesIsFirst == TCL_ERROR)
687 Tcl_AppendResult(interp, "\n", NULL);
688 else
689 namesIsFirst = TCL_ERROR;
690 logDest = logDests[i];
691 Tcl_AppendResult(interp,
692 name, " ",
693 logDest->filter->facility, ".",
694 getSeverityName(logDest->filter->
695 minSeverity), "-",
696 getSeverityName(logDest->filter->
697 maxSeverity), NULL);
698 Tcl_Free(name);
699 }
700 }
701 }
702 return TCL_OK;
703 }
704 case DELETE:{
705
706 /* 0 1 2 */
707 /* web::loglogDest delete logDest1 */
708
709 switch (objc) {
710 case 3: {
711 LogDest ** logDests = logData->listOfDests;
712 if (!strcmp("-requests", Tcl_GetString(objv[2]))) {
713 /* special case: delete all destinations NOT created during web::initializer */
714 int i;
715 for (i = 0; i < logData->destSize; i++) {
716 if (logDests[i] != NULL && !logDests[i]->keep) {
717 destroyLogDest(logDests[i], interp);
718 logDests[i] = NULL;
719 }
720 }
721 return TCL_OK;
722 } else {
723 int inx = getIndexFromLogName(LOG_DEST_PREFIX"%d", Tcl_GetString(objv[2]));
724 if (inx < 0
725 || inx >= logData->destSize
726 || logDests[inx] == NULL) {
727 Tcl_SetResult(interp, "no such log destination \"", NULL);
728 Tcl_AppendResult(interp, Tcl_GetString(objv[2]), "\"",
729 NULL);
730 return TCL_ERROR;
731 }
732 destroyLogDest(logDests[inx], interp);
733 logDests[inx] = NULL;
734 return TCL_OK;
735 break;
736 }
737 }
738 case 2:
739 /* --------------------------------------------------------
740 * no argument --> resets the list
741 * -------------------------------------------------------- */
742 if (logData->listOfDests != NULL) {
743 int i;
744 LogDest ** logDests = logData->listOfDests;
745 for (i = 0; i < logData->destSize; i++) {
746 if (logDests[i] != NULL) {
747 destroyLogDest(logDests[i], interp);
748 logDests[i] = NULL;
749 }
750 }
751 }
752 return TCL_OK;
753 break;
754 default:
755 Tcl_WrongNumArgs(interp, 1, objv, "delete ?destname?");
756 return TCL_ERROR;
757 }
758 break;
759 }
760 default:
761 return TCL_OK;
762 }
763 }
764
765
766 /* ----------------------------------------------------------------------------
767 * Web_LogFilter -- manage list of filters
768 * ------------------------------------------------------------------------- */
Web_LogFilter(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])769 int Web_LogFilter(ClientData clientData,
770 Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[])
771 {
772
773 LogData *logData;
774 int idx;
775
776 static TCLCONST char *subCommands[] = {
777 WEB_LOG_SUBCMD_ADD,
778 WEB_LOG_SUBCMD_DELETE,
779 WEB_LOG_SUBCMD_NAMES,
780 WEB_LOG_SUBCMD_LEVELS,
781 NULL
782 };
783 enum subCommands
784 { ADD, DELETE, NAMES, LEVELS };
785
786 /* --------------------------------------------------------------------------
787 * check for internal data
788 * ----------------------------------------------------------------------- */
789 WebAssertData(interp, clientData, "Web_LogFilter", TCL_ERROR)
790 logData = (LogData *) clientData;
791
792 /* --------------------------------------------------------------------------
793 * enough arguments ?
794 * ----------------------------------------------------------------------- */
795 if (objc < 2) {
796 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
797 return TCL_ERROR;
798 }
799
800 /* ------------------------------------------------------------------------
801 * check subcommand
802 * --------------------------------------------------------------------- */
803 if (Tcl_GetIndexFromObj(interp, objv[1], subCommands, "option", 0, &idx)
804 != TCL_OK) {
805 return TCL_ERROR;
806 }
807
808 switch ((enum subCommands) idx) {
809 case ADD:{
810
811 /* ------------------------------------------------------------------------
812 * web::loglevel add sytnax is as follows:
813 * web::loglevel add level
814 * 0 1 2
815 * --------------------------------------------------------------------- */
816 LogLevel *logLevel = NULL;
817 char *name = NULL;
818
819 /* ------------------------------------------------------------------------
820 * enough arguments ?
821 * --------------------------------------------------------------------- */
822 if (objc != 3) {
823 Tcl_WrongNumArgs(interp, 2, objv, "level");
824 return TCL_ERROR;
825 }
826
827 /* ------------------------------------------------------------------------
828 * parse level
829 * --------------------------------------------------------------------- */
830 logLevel =
831 parseLogLevel(interp, Tcl_GetString(objv[2]), "user", -1);
832 if (logLevel == NULL) {
833 WebFreeIfNotNull(name);
834 return TCL_ERROR;
835 }
836 logLevel->keep = logData->keep;
837
838 /* ------------------------------------------------------------------------
839 * and add to list
840 * --------------------------------------------------------------------- */
841 name = insertIntoFilterList(logData, logLevel);
842 if (name == NULL) {
843 Tcl_SetResult(interp, "cannot append new log filter to list", NULL);
844 destroyLogLevel(logLevel, NULL);
845 return TCL_ERROR;
846 }
847 Tcl_SetResult(interp, name, Tcl_Free);
848 return TCL_OK;
849 break;
850 }
851 case NAMES:{
852
853 Tcl_ResetResult(interp);
854
855 if (logData->listOfFilters != NULL) {
856 int i;
857 LogLevel **logLevels = logData->listOfFilters;
858 for (i = 0; i < logData->filterSize; i++) {
859 if (logLevels[i] != NULL) {
860 char * name = createLogName(LOG_FILTER_PREFIX, i);
861 if (name != NULL) {
862 Tcl_AppendElement(interp, name);
863 Tcl_Free(name);
864 }
865 }
866 }
867 }
868 return TCL_OK;
869 break;
870 }
871
872 case LEVELS:{
873
874 LogLevel *logLevel = NULL;
875 int namesIsFirst = TCL_OK;
876
877 Tcl_SetResult(interp, "", NULL);
878
879 if (logData->listOfFilters != NULL) {
880 int i;
881 LogLevel ** logLevels = logData->listOfFilters;
882 for (i = 0; i < logData->filterSize; i++) {
883 if (logLevels[i] != NULL) {
884 char * name = createLogName(LOG_FILTER_PREFIX, i);
885 if (namesIsFirst == TCL_ERROR)
886 Tcl_AppendResult(interp, "\n", NULL);
887 else
888 namesIsFirst = TCL_ERROR;
889 logLevel = logLevels[i];
890 Tcl_AppendResult(interp,
891 name, " ",
892 logLevel->facility, ".",
893 getSeverityName(logLevel->minSeverity),
894 "-",
895 getSeverityName(logLevel->maxSeverity),
896 NULL);
897 Tcl_Free(name);
898 }
899 }
900 }
901 return TCL_OK;
902 break;
903 }
904 case DELETE:{
905
906 /* 0 1 2 */
907 /* web::loglevel delete logLevel1 */
908
909 switch (objc) {
910 case 3: {
911 LogLevel ** logLevels = logData->listOfFilters;
912 if (!strcmp("-requests", Tcl_GetString(objv[2]))) {
913 /* special case: delete all levels NOT created during web::initializer */
914 int i;
915 for (i = 0; i < logData->filterSize; i++) {
916 if (logLevels[i] != NULL && !logLevels[i]->keep) {
917 destroyLogLevel(logLevels[i], interp);
918 logLevels[i] = NULL;
919 }
920 }
921 return TCL_OK;
922 } else {
923 int inx = getIndexFromLogName(LOG_FILTER_PREFIX"%d", Tcl_GetString(objv[2]));
924 if (inx < 0
925 || inx >= logData->filterSize
926 || logLevels[inx] == NULL) {
927 Tcl_SetResult(interp, "no such log filter \"", NULL);
928 Tcl_AppendResult(interp, Tcl_GetString(objv[2]), "\"",
929 NULL);
930 return TCL_ERROR;
931 }
932 destroyLogLevel(logLevels[inx], interp);
933 logLevels[inx] = NULL;
934 return TCL_OK;
935 break;
936 }
937 }
938 case 2:
939 /* -----------------------------------------------------
940 * no argument --> resets the list
941 * ----------------------------------------------------- */
942 if (logData->listOfFilters != NULL) {
943 int i;
944 LogLevel ** logLevels = logData->listOfFilters;
945 for (i = 0; i < logData->filterSize; i++) {
946 if (logLevels[i] != NULL) {
947 destroyLogLevel(logLevels[i], interp);
948 logLevels[i] = NULL;
949 }
950 }
951 }
952 return TCL_OK;
953 break;
954 default:
955 Tcl_WrongNumArgs(interp, 1, objv, "delete ?filtername?");
956 return TCL_ERROR;
957 }
958 break;
959 }
960 default:
961 return TCL_OK;
962 }
963 }
964
965 /* ----------------------------------------------------------------------------
966 * createLogPlugIn --
967 * ------------------------------------------------------------------------- */
createLogPlugIn()968 LogPlugIn DLLEXPORT *createLogPlugIn()
969 {
970
971 LogPlugIn *logPlugIn = NULL;
972
973 logPlugIn = WebAllocInternalData(LogPlugIn);
974 if (logPlugIn != NULL) {
975 logPlugIn->constructor = NULL;
976 logPlugIn->destructor = NULL;
977 logPlugIn->handler = NULL;
978 }
979 return logPlugIn;
980 }
981
982 /* ----------------------------------------------------------------------------
983 * destroyLogPlugIn --
984 * ------------------------------------------------------------------------- */
destroyLogPlugIn(void * plugIn,void * dum)985 int destroyLogPlugIn(void *plugIn, void *dum)
986 {
987
988 LogPlugIn *logPlugIn = (LogPlugIn *) plugIn;
989
990 if (logPlugIn != NULL) {
991 WebFreeIfNotNull(logPlugIn);
992 } else {
993 fprintf(stderr, "destroyLogPlugin: plugin doesn't exist.\n");
994 }
995 return TCL_OK;
996 }
997
998
999 /* ----------------------------------------------------------------------------
1000 * registerLogPlugIn --
1001 * ------------------------------------------------------------------------- */
registerLogPlugIn(Tcl_Interp * interp,char * type,LogPlugIn * logPlugIn)1002 int DLLEXPORT registerLogPlugIn(Tcl_Interp * interp, char *type, LogPlugIn * logPlugIn)
1003 {
1004
1005 LogData *logData;
1006
1007 if ((interp == NULL) || (logPlugIn == NULL) || (type == NULL))
1008 return TCL_ERROR;
1009
1010 /* --------------------------------------------------------------------------
1011 * try to get the logData data
1012 * ----------------------------------------------------------------------- */
1013 logData = (LogData *) Tcl_GetAssocData(interp, WEB_LOG_ASSOC_DATA, NULL);
1014 WebAssertData(interp, logData, "log", TCL_ERROR)
1015
1016 /* --------------------------------------------------------------------------
1017 * append
1018 * ----------------------------------------------------------------------- */
1019 if (logData->listOfPlugIns == NULL)
1020 return TCL_ERROR;
1021 return appendToHashTable(logData->listOfPlugIns, type,
1022 (ClientData) logPlugIn);
1023 }
1024
1025 /* ----------------------------------------------------------------------------
1026 * LOG_MSG -- write log message to webshell log facility
1027 * <interp> interp (needed to access log module data)
1028 * <flag> use WRITE_LOG , SET_RESULT, INTERP_ERRORINFO
1029 * <filename> of caller "test.c"
1030 * <linenr> of caller "123"
1031 * <cmd> caller "testCommand"
1032 * <level> webshell log level
1033 * <msg> message parts (NULL-terminated list)
1034 * ------------------------------------------------------------------------- */
LOG_MSG(Tcl_Interp * interp,int flag,char * filename,int linenr,char * cmd,char * level,char * msg,...)1035 void DLLEXPORT LOG_MSG(Tcl_Interp * interp, int flag, char *filename, int linenr,
1036 char *cmd, char *level, char *msg, ...)
1037 {
1038
1039 Tcl_Obj *errobj = NULL;
1040 Tcl_Obj *resobj = NULL;
1041 #ifdef DEBUG
1042 Tcl_Obj *debugobj = NULL;
1043 #endif
1044 char *msgpart = NULL;
1045
1046 va_list ap;
1047
1048 errobj = Tcl_NewObj();
1049 Tcl_IncrRefCount(errobj);
1050
1051 resobj = Tcl_NewObj();
1052 Tcl_IncrRefCount(resobj);
1053
1054 if (interp == NULL)
1055 Tcl_AppendToObj(errobj, "interp = null", -1);
1056
1057 #ifdef DEBUG
1058 debugobj = Tcl_NewIntObj(linenr);
1059 Tcl_IncrRefCount(debugobj);
1060 Tcl_AppendStringsToObj(errobj, "File:", filename,
1061 ", Line:", Tcl_GetString(debugobj),
1062 ", ", (char *) NULL);
1063 #endif
1064
1065 Tcl_AppendStringsToObj(errobj, cmd, ": ", msg, (char *) NULL);
1066
1067 if (flag & SET_RESULT)
1068 Tcl_AppendStringsToObj(resobj, msg, NULL);
1069
1070 for (va_start(ap, msg); (msgpart = va_arg(ap, char *)) != NULL;) {
1071 Tcl_AppendStringsToObj(errobj, msgpart, NULL);
1072 if (flag & SET_RESULT)
1073 Tcl_AppendStringsToObj(resobj, msgpart, NULL);
1074 }
1075
1076 va_end(ap);
1077
1078 if (interp != NULL && (flag & WRITE_LOG)) {
1079 webLog(interp, level, Tcl_GetString(errobj));
1080 }
1081
1082 #ifdef WRITE_TO_STDOUT
1083 printf("%s\n", Tcl_GetString(errobj));
1084 fflush(stdout);
1085 #endif
1086
1087 if ((flag & INTERP_ERRORINFO) && (interp != NULL)) {
1088 char *errorInfo = (char *) Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1089 if (errorInfo != NULL)
1090 webLog(interp, WEBLOG_DEBUG, errorInfo);
1091 else
1092 webLog(interp, WEBLOG_DEBUG, "panic: errorInfo not set");
1093 }
1094
1095 if (flag & SET_RESULT)
1096 Tcl_SetObjResult(interp, resobj);
1097
1098 Tcl_DecrRefCount(errobj);
1099 Tcl_DecrRefCount(resobj); /* ok, ref count was incremented before */
1100 #ifdef DEBUG
1101 Tcl_DecrRefCount(debugobj);
1102 #endif
1103 }
1104