Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

klog.c

00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: klog.c,v 1.27 2006/01/11 14:19:21 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <time.h>
00013 #include <u/libu.h>
00014 #include <klone/klog.h>
00015 #include <klone/klogprv.h>
00016 
00017 static int klog_args_new (klog_args_t **pka);
00018 static int klog_args_check (klog_args_t *ka);
00019 
00020 static int klog_type (const char *type);
00021 static int klog_facility (const char *fac);
00022 static int klog_threshold (const char *threshold);
00023 static int klog_logopt (const char *options);
00024 
00025 
00037 int klog_args (u_config_t *ls, klog_args_t **pka)
00038 {
00039     const char *cs;
00040     klog_args_t *ka = NULL;
00041 
00042     dbg_return_if (ls == NULL, ~0);
00043     dbg_return_if (pka == NULL, ~0);
00044 
00045     /* here defaults are set */
00046     dbg_err_if (klog_args_new(&ka));
00047 
00048     /* read in config values */
00049     ka->type = klog_type(u_config_get_subkey_value(ls, "type"));
00050 
00051     if ((cs = u_config_get_subkey_value(ls, "ident")) != NULL)
00052         ka->ident = u_strdup(cs);
00053 
00054     ka->threshold = klog_threshold(u_config_get_subkey_value(ls, "threshold"));
00055 
00056     if ((cs = u_config_get_subkey_value(ls, "memory.limit")) != NULL)
00057         ka->mlimit = atoi(cs);
00058 
00059     if ((cs = u_config_get_subkey_value(ls, "file.basename")) != NULL) 
00060         ka->fbasename = u_strdup(cs);
00061 
00062     if ((cs = u_config_get_subkey_value(ls, "file.limit")) != NULL)
00063         ka->flimit = atoi(cs);
00064 
00065     if ((cs = u_config_get_subkey_value(ls, "file.splits")) != NULL)
00066         ka->fsplits = atoi(cs);
00067 
00068     #ifdef HAVE_SYSLOG
00069     ka->sfacility = 
00070         klog_facility(u_config_get_subkey_value(ls, "syslog.facility"));
00071 
00072     ka->soptions = klog_logopt(u_config_get_subkey_value(ls, "syslog.options"));
00073     #endif
00074 
00075     dbg_return_if (klog_args_check(ka), ~0);
00076 
00077     *pka = ka;
00078     
00079     return 0;
00080 err:
00081     if (ka)
00082         klog_args_free(ka);
00083     return ~0;
00084 }
00085 
00096 int klog_open (klog_args_t *ka, klog_t **pkl)
00097 {
00098     int rv;
00099     klog_t *kl = NULL;
00100 
00101     dbg_return_if (pkl == NULL, ~0);
00102     dbg_return_if (ka == NULL, ~0);
00103 
00104     /* create a klog_t object: each per-type init will create and stick 
00105      * its klog_*_t obj */
00106     dbg_err_if (klog_new(ka->type, ka->threshold, ka->ident, &kl));
00107 
00108     switch (ka->type)
00109     {
00110         case KLOG_TYPE_MEM:
00111             rv = klog_open_mem(kl, ka->mlimit);
00112             break;
00113         case KLOG_TYPE_FILE:
00114             rv = klog_open_file(kl, ka->fbasename, ka->fsplits, ka->flimit);
00115             break;
00116         #ifdef HAVE_SYSLOG
00117         case KLOG_TYPE_SYSLOG:
00118             rv = klog_open_syslog(kl, ka->sfacility, ka->soptions);
00119             break;
00120         #endif
00121         default:
00122             return ~0;
00123     }
00124 
00125     dbg_err_if (rv);
00126     *pkl = kl;
00127     
00128     return 0;
00129 err:
00130     klog_close(kl);
00131     return ~0;
00132 }
00133 
00149 int klog (klog_t *kl, int level, const char *fmt, ...)
00150 {
00151     va_list ap;
00152     int rv = 0;
00153 
00154     dbg_return_if (kl == NULL, ~0);
00155     dbg_return_if (fmt == NULL, ~0);
00156     dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0);
00157 
00158     va_start(ap, fmt);
00159     
00160     /* get rid of spurious stuff */
00161     dbg_goto_if (level < KLOG_DEBUG || level >= KLOG_LEVEL_UNKNOWN, end);
00162 
00163     /* early filtering of msgs with level lower than threshold */
00164     if (level < kl->threshold)
00165         goto end;
00166     
00167     /* if the log function is set call it with the supplied args */
00168     if (kl->cb_log)
00169         rv = kl->cb_log(kl, level, fmt, ap);
00170 
00171 end:
00172     va_end(ap);
00173 
00174     return rv;
00175 }
00176 
00184 void klog_close (klog_t *kl)
00185 {
00186     if (kl == NULL) 
00187         return;
00188     if (!IS_KLOG_TYPE(kl->type)) 
00189         return;
00190 
00191     /* call private close function */
00192     if (kl->cb_close)
00193         kl->cb_close(kl);
00194 
00195     U_FREE(kl);
00196 
00197     return;
00198 }
00199 
00212 int klog_getln (klog_t *kl, size_t nth, char ln[])
00213 {
00214     dbg_return_if (kl == NULL, ~0);
00215     dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0);
00216 
00217     if (kl->cb_getln)
00218         return kl->cb_getln(kl, nth, ln);
00219     
00220     return 0;
00221 }
00222 
00232 int klog_clear (klog_t *kl)
00233 {
00234     dbg_return_if (kl == NULL, ~0);
00235     dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0);
00236 
00237     if (kl->cb_clear)
00238         return kl->cb_clear(kl);
00239 
00240     return ~0;
00241 }
00242 
00250 ssize_t klog_countln (klog_t *kl)
00251 {
00252     dbg_return_if (kl == NULL, -1);
00253     dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0);
00254 
00255     if (kl->cb_countln)
00256         return kl->cb_countln(kl);
00257 
00258     return -1;      /* XXX should be 0 ? */
00259 }
00260 
00272 int klog_open_from_config(u_config_t *ls, klog_t **pkl)
00273 {
00274     klog_t *kl = NULL;
00275     klog_args_t *kargs = NULL;
00276 
00277     /* parse config parameters */
00278     dbg_err_if(klog_args(ls, &kargs));
00279 
00280     /* create a klog object */
00281     dbg_err_if(klog_open(kargs, &kl));
00282 
00283     klog_args_free(kargs);
00284     kargs = NULL;
00285 
00286     /* stick it */
00287     *pkl = kl;
00288 
00289     return 0;
00290 err:
00291     if(kargs)
00292         klog_args_free(kargs);
00293     if(kl)
00294         klog_close(kl);
00295     return ~0;
00296 }
00297 
00307 int klog_flush (klog_t *kl)
00308 {
00309     dbg_return_if (kl == NULL, ~0);
00310     dbg_return_if (!IS_KLOG_TYPE(kl->type), ~0);
00311 
00312     /* call private flush function */
00313     if (kl->cb_flush)
00314         return kl->cb_flush(kl);
00315 
00316     return 0;
00317 }
00318 
00319 
00320 /* just for testing */
00321 void klog_args_print (FILE *fp, klog_args_t *ka)
00322 {
00323     dbg_ifb (ka == NULL) return;
00324     dbg_ifb (fp == NULL) return;
00325 
00326     fprintf(fp, "ka->type: \t %d\n", ka->type);
00327     fprintf(fp, "ka->ident: \t %s\n", ka->ident);
00328     fprintf(fp, "ka->threshold: \t %d\n", ka->threshold);
00329     fprintf(fp, "ka->mlimit: \t %zd\n", ka->mlimit);
00330     fprintf(fp, "ka->fbasename: \t %s\n", ka->fbasename);
00331     fprintf(fp, "ka->fsplits: \t %zd\n", ka->fsplits);
00332     fprintf(fp, "ka->flimit: \t %zd\n", ka->flimit);
00333     fprintf(fp, "ka->soptions: \t %d\n", ka->soptions);
00334     fprintf(fp, "ka->sfacility: \t %d\n", ka->sfacility);
00335 
00336     return;
00337 }
00338 
00339 void klog_args_free (klog_args_t *ka)
00340 {
00341     U_FREE(ka->ident);
00342     U_FREE(ka->fbasename);
00343     U_FREE(ka);
00344     return;
00345 }
00346 
00347 /* map type directive to the internal representation */
00348 static int klog_type (const char *type)
00349 {
00350     dbg_return_if (type == NULL, KLOG_TYPE_UNKNOWN);
00351 
00352     if (!strcasecmp(type, "memory"))
00353         return KLOG_TYPE_MEM;
00354     else if (!strcasecmp(type, "file"))
00355         return KLOG_TYPE_FILE;
00356     else if (!strcasecmp(type, "syslog"))
00357         return KLOG_TYPE_SYSLOG;
00358     else
00359         return KLOG_TYPE_UNKNOWN;
00360 }
00361 
00362 /* map threshold directive to the internal representation */
00363 static int klog_threshold (const char *threshold)
00364 {
00365     int i;
00366 
00367     dbg_return_if (threshold == NULL, KLOG_LEVEL_UNKNOWN);
00368 
00369     for (i = KLOG_DEBUG; i <= KLOG_EMERG; i++)
00370         if (!strcasecmp(threshold, kloglev[i]))
00371             return i;
00372 
00373     warn("bad threshold value: \'%s\'", threshold);
00374     return KLOG_LEVEL_UNKNOWN;
00375 }
00376 
00377 #ifdef HAVE_SYSLOG
00378 /* map threshold directive to the internal representation */
00379 static int klog_logopt (const char *options)
00380 {
00381     char *o2 = NULL;    /* 'options' dupped for safe u_tokenize() */
00382     int i, logopt = 0;
00383     enum { NOPTS = 4 };
00384     char *optv[NOPTS + 1];
00385     
00386     dbg_return_if (options == NULL, 0);
00387     dbg_return_if ((o2 = u_strdup(options)) == NULL, 0);
00388 
00389     dbg_err_if (u_tokenize(o2, " \t", optv, NOPTS + 1));
00390     
00391     for (i = 0; optv[i] != NULL; i++)
00392     {
00393         if (!strcasecmp(optv[i], "LOG_CONS"))
00394             logopt |= LOG_CONS;
00395         else if (!strcasecmp(optv[i], "LOG_NDELAY"))
00396             logopt |= LOG_NDELAY;
00397         else if (!strcasecmp(optv[i], "LOG_PERROR"))
00398             logopt |= LOG_PERROR;
00399         else if (!strcasecmp(optv[i], "LOG_PID"))
00400             logopt |= LOG_PID;
00401         else
00402             warn("bad log option: \'%s\'", optv[i]);
00403     }
00404 
00405     U_FREE(o2);
00406     return logopt;
00407 
00408 err:
00409     U_FREE(o2);
00410     return 0;
00411 }
00412 #endif
00413 
00414 /* map LOG_LOCAL[0-7] strings into syslog(3) #define'd values */
00415 static int klog_facility (const char *fac)
00416 {
00417     dbg_err_if (fac == NULL);
00418 
00419     if (!strcasecmp(fac, "LOG_LOCAL0")) 
00420         return LOG_LOCAL0;
00421     else if (!strcasecmp(fac, "LOG_LOCAL1")) 
00422         return LOG_LOCAL1;
00423     else if (!strcasecmp(fac, "LOG_LOCAL2")) 
00424         return LOG_LOCAL2;
00425     else if (!strcasecmp(fac, "LOG_LOCAL3")) 
00426         return LOG_LOCAL3;
00427     else if (!strcasecmp(fac, "LOG_LOCAL4")) 
00428         return LOG_LOCAL4;
00429     else if (!strcasecmp(fac, "LOG_LOCAL5")) 
00430         return LOG_LOCAL5;
00431     else if (!strcasecmp(fac, "LOG_LOCAL6")) 
00432         return LOG_LOCAL6;
00433     else if (!strcasecmp(fac, "LOG_LOCAL7")) 
00434         return LOG_LOCAL7;
00435 
00436 err:    
00437     warn("bad facility value \'%s\'", fac);
00438     return KLOG_FACILITY_UNKNOWN; 
00439 }
00440 
00441 static int klog_args_new (klog_args_t **pka)
00442 {
00443     dbg_return_if (pka == NULL, ~0);
00444 
00445     *pka = u_zalloc(sizeof(klog_args_t));
00446     dbg_return_if (*pka == NULL, ~0);
00447 
00448     return 0;
00449 }
00450 
00451 static int klog_args_check (klog_args_t *ka)
00452 {
00453     dbg_return_if (ka == NULL, ~0);
00454 
00455     if (ka->type == KLOG_TYPE_UNKNOWN)
00456         warn_err("unknown log type");
00457 
00458     /* do not filter if not specified or if a wrong value has been supplied */
00459     if (ka->threshold == KLOG_LEVEL_UNKNOWN)
00460     {
00461         warn("threshold unspecified: assuming lowest possible (DEBUG)");
00462         ka->threshold = KLOG_DEBUG;
00463     }
00464 
00465     switch (ka->type)
00466     {
00467         case KLOG_TYPE_MEM:
00468             if (ka->mlimit == 0)
00469                 ka->mlimit = KLOG_MLIMIT_DFL;
00470             break;
00471         case KLOG_TYPE_FILE:
00472             if (ka->fbasename == NULL)
00473                 warn_err("log file path is mandatory !");
00474             if (ka->fsplits == 0)
00475                 ka->fsplits =  KLOG_FSPLITS_DFL;
00476             if (ka->flimit == 0)
00477                 ka->flimit = KLOG_FLIMIT_DFL;
00478             break;
00479         case KLOG_TYPE_SYSLOG:
00480             if (ka->sfacility == KLOG_FACILITY_UNKNOWN)
00481             {
00482                 warn("facility unspecified: defaults to LOG_LOCAL7");
00483                 ka->sfacility = LOG_LOCAL7;
00484             }
00485             break;
00486         default:
00487             warn_err("what are you doing here ?");
00488     }
00489 
00490     return 0;
00491 err:
00492     return ~0;
00493 }
00494 
00495