📄 log.c
字号:
isc_dir_init(&dir); result = isc_dir_open(&dir, dirname); /* * Replace the file separator if it was taken out. */ if (basename != FILE_NAME(channel)) *(basename - 1) = sep; /* * Return if the directory open failed. */ if (result != ISC_R_SUCCESS) return (result); while (isc_dir_read(&dir) == ISC_R_SUCCESS) { if (dir.entry.length > basenamelen && strncmp(dir.entry.name, basename, basenamelen) == 0 && dir.entry.name[basenamelen] == '.') { version = strtol(&dir.entry.name[basenamelen + 1], &digit_end, 10); if (*digit_end == '\0' && version > greatest) greatest = version; } } isc_dir_close(&dir); *greatestp = ++greatest; return (ISC_R_SUCCESS);}static isc_result_troll_log(isc_logchannel_t *channel) { int i, n, greatest; char current[PATH_MAX + 1]; char new[PATH_MAX + 1]; const char *path; isc_result_t result; /* * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER * is specified. Apparently complete external control over the log * files is desired. */ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) return (ISC_R_SUCCESS); path = FILE_NAME(channel); /* * Set greatest_version to the greatest existing version * (not the maximum requested version). This is 1 based even * though the file names are 0 based, so an oldest log of log.1 * is a greatest_version of 2. */ result = greatest_version(channel, &greatest); if (result != ISC_R_SUCCESS) return (result); /* * Now greatest should be set to the highest version number desired. * Since the highest number is one less than FILE_VERSIONS(channel) * when not doing infinite log rolling, greatest will need to be * decremented when it is equal to -- or greater than -- * FILE_VERSIONS(channel). When greatest is less than * FILE_VERSIONS(channel), it is already suitable for use as * the maximum version number. */ if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE || FILE_VERSIONS(channel) > greatest) ; /* Do nothing. */ else /* * When greatest is >= FILE_VERSIONS(channel), it needs to * be reduced until it is FILE_VERSIONS(channel) - 1. * Remove any excess logs on the way to that value. */ while (--greatest >= FILE_VERSIONS(channel)) { n = snprintf(current, sizeof(current), "%s.%d", path, greatest); if (n >= (int)sizeof(current) || n < 0) result = ISC_R_NOSPACE; else result = isc_file_remove(current); if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) syslog(LOG_ERR, "unable to remove log file '%s.%d': %s", path, greatest, isc_result_totext(result)); } for (i = greatest; i > 0; i--) { result = ISC_R_SUCCESS; n = snprintf(current, sizeof(current), "%s.%d", path, i - 1); if (n >= (int)sizeof(current) || n < 0) result = ISC_R_NOSPACE; if (result == ISC_R_SUCCESS) { n = snprintf(new, sizeof(new), "%s.%d", path, i); if (n >= (int)sizeof(new) || n < 0) result = ISC_R_NOSPACE; } if (result == ISC_R_SUCCESS) result = isc_file_rename(current, new); if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) syslog(LOG_ERR, "unable to rename log file '%s.%d' to " "'%s.%d': %s", path, i - 1, path, i, isc_result_totext(result)); } if (FILE_VERSIONS(channel) != 0) { n = snprintf(new, sizeof(new), "%s.0", path); if (n >= (int)sizeof(new) || n < 0) result = ISC_R_NOSPACE; else result = isc_file_rename(path, new); if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) syslog(LOG_ERR, "unable to rename log file '%s' to '%s.0': %s", path, path, isc_result_totext(result)); } else { result = isc_file_remove(path); if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) syslog(LOG_ERR, "unable to remove log file '%s': %s", path, isc_result_totext(result)); } return (ISC_R_SUCCESS);}static isc_result_tisc_log_open(isc_logchannel_t *channel) { struct stat statbuf; isc_boolean_t regular_file; isc_boolean_t roll = ISC_FALSE; isc_result_t result = ISC_R_SUCCESS; const char *path; REQUIRE(channel->type == ISC_LOG_TOFILE); REQUIRE(FILE_STREAM(channel) == NULL); path = FILE_NAME(channel); REQUIRE(path != NULL && *path != '\0'); /* * Determine type of file; only regular files will be * version renamed, and only if the base file exists * and either has no size limit or has reached its size limit. */ if (stat(path, &statbuf) == 0) { regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE; /* XXXDCL if not regular_file complain? */ if ((FILE_MAXSIZE(channel) == 0 && FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) || (FILE_MAXSIZE(channel) > 0 && statbuf.st_size >= FILE_MAXSIZE(channel))) roll = regular_file; } else if (errno == ENOENT) regular_file = ISC_TRUE; else result = ISC_R_INVALIDFILE; /* * Version control. */ if (result == ISC_R_SUCCESS && roll) { if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) return (ISC_R_MAXSIZE); result = roll_log(channel); if (result != ISC_R_SUCCESS) { if ((channel->flags & ISC_LOG_OPENERR) == 0) { syslog(LOG_ERR, "isc_log_open: roll_log '%s' " "failed: %s", FILE_NAME(channel), isc_result_totext(result)); channel->flags |= ISC_LOG_OPENERR; } return (result); } } result = isc_stdio_open(path, "a", &FILE_STREAM(channel)); return (result);}isc_boolean_tisc_log_wouldlog(isc_log_t *lctx, int level) { /* * Try to avoid locking the mutex for messages which can't * possibly be logged to any channels -- primarily debugging * messages that the debug level is not high enough to print. * * If the level is (mathematically) less than or equal to the * highest_level, or if there is a dynamic channel and the level is * less than or equal to the debug level, the main loop must be * entered to see if the message should really be output. * * NOTE: this is UNLOCKED access to the logconfig. However, * the worst thing that can happen is that a bad decision is made * about returning without logging, and that's not a big concern, * because that's a risk anyway if the logconfig is being * dynamically changed. */ if (lctx == NULL || lctx->logconfig == NULL) return (ISC_FALSE); return (ISC_TF(level <= lctx->logconfig->highest_level || (lctx->logconfig->dynamic && level <= lctx->debug_level)));}static voidisc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, isc_logmodule_t *module, int level, isc_boolean_t write_once, isc_msgcat_t *msgcat, int msgset, int msg, const char *format, va_list args){ int syslog_level; char time_string[64]; char level_string[24]; const char *iformat; struct stat statbuf; isc_boolean_t matched = ISC_FALSE; isc_boolean_t printtime, printtag; isc_boolean_t printcategory, printmodule, printlevel; isc_logconfig_t *lcfg; isc_logchannel_t *channel; isc_logchannellist_t *category_channels; isc_result_t result; REQUIRE(lctx == NULL || VALID_CONTEXT(lctx)); REQUIRE(category != NULL); REQUIRE(module != NULL); REQUIRE(level != ISC_LOG_DYNAMIC); REQUIRE(format != NULL); /* * Programs can use libraries that use this logging code without * wanting to do any logging, thus the log context is allowed to * be non-existent. */ if (lctx == NULL) return; REQUIRE(category->id < lctx->category_count); REQUIRE(module->id < lctx->module_count); if (! isc_log_wouldlog(lctx, level)) return; if (msgcat != NULL) iformat = isc_msgcat_get(msgcat, msgset, msg, format); else iformat = format; time_string[0] = '\0'; level_string[0] = '\0'; LOCK(&lctx->lock); lctx->buffer[0] = '\0'; lcfg = lctx->logconfig; category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]); /* * XXXDCL add duplicate filtering? (To not write multiple times to * the same source via various channels). */ do { /* * If the channel list end was reached and a match was made, * everything is finished. */ if (category_channels == NULL && matched) break; if (category_channels == NULL && ! matched && category_channels != ISC_LIST_HEAD(lcfg->channellists[0])) /* * No category/module pair was explicitly configured. * Try the category named "default". */ category_channels = ISC_LIST_HEAD(lcfg->channellists[0]); if (category_channels == NULL && ! matched) /* * No matching module was explicitly configured * for the category named "default". Use the internal * default channel. */ category_channels = &default_channel; if (category_channels->module != NULL && category_channels->module != module) { category_channels = ISC_LIST_NEXT(category_channels, link); continue; } matched = ISC_TRUE; channel = category_channels->channel; category_channels = ISC_LIST_NEXT(category_channels, link); if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && lctx->debug_level == 0) continue; if (channel->level == ISC_LOG_DYNAMIC) { if (lctx->debug_level < level) continue; } else if (channel->level < level) continue; if ((channel->flags & ISC_LOG_PRINTTIME) != 0 && time_string[0] == '\0') { isc_time_t isctime; TIME_NOW(&isctime); isc_time_formattimestamp(&isctime, time_string, sizeof(time_string)); } if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 && level_string[0] == '\0') { if (level < ISC_LOG_CRITICAL) snprintf(level_string, sizeof(level_string), isc_msgcat_get(isc_msgcat, ISC_MSGSET_LOG, ISC_MSG_LEVEL, "level %d: "), level); else if (level > ISC_LOG_DYNAMIC) snprintf(level_string, sizeof(level_string), "%s %d: ", log_level_strings[0], level); else snprintf(level_string, sizeof(level_string), "%s: ", log_level_strings[-level]); } /* * Only format the message once. */ if (lctx->buffer[0] == '\0') { (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer), iformat, args); /* * Check for duplicates. */ if (write_once) { isc_logmessage_t *message, *new; isc_time_t oldest; isc_interval_t interval; isc_interval_set(&interval, lcfg->duplicate_interval, 0); /* * 'oldest' is the age of the oldest messages * which fall within the duplicate_interval * range. */ TIME_NOW(&oldest); if (isc_time_subtract(&oldest, &interval, &oldest) != ISC_R_SUCCESS) /* * Can't effectively do the checking * without having a valid time. */ message = NULL; else message =ISC_LIST_HEAD(lctx->messages); while (message != NULL) { if (isc_time_compare(&message->time, &oldest) < 0) { /* * This message is older * than the duplicate_interval, * so it should be dropped from * the history. * * Setting the interval to be * to be longer will obviously * not cause the expired * message to spring back into * existence. */ new = ISC_LIST_NEXT(message, link); ISC_LIST_UNLINK(lctx->messages, message, link); isc_mem_put(lctx->mctx, message, sizeof(*message) + 1 + strlen(message->text)); message = new; continue; } /* * This message is in the duplicate * filtering interval ... */ if (strcmp(lctx->buffer, message->text) == 0) { /* * ... and it is a duplicate. * Unlock the mutex and * get the hell out of Dodge. */ UNLOCK(&lctx->lock); return; } message = ISC_LIST_NEXT(message, link); } /* * It wasn't in the duplicate interval, * so add it to the message list. */ new = isc_mem_get(lctx->mctx, sizeof(isc_logmessage_t) + strlen(lctx->buffer) + 1); if (new != NULL) { /* * Put the text immediately after * the struct. The strcpy is safe. */ new->text = (char *)(new + 1); strcpy(new->text, lctx->buffer); TIME_NOW(&new->time); ISC_LIST_APPEND(lctx->messages, new, link); } } } printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME) != 0); printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG) != 0 && lcfg->tag != NULL); printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY) != 0); printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE) != 0); printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL) != 0); switch (channel->type) { case ISC_LOG_TOFILE: if (FILE_MAXREACHED(channel)) { /* * If the file can be rolled, OR * If the file no longer exists, OR * If the file is less than the maximum size, * (such as if it had been renamed and * a new one touched, or it was truncated * in place) * ... then close it to trigger reopening. */ if (FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER || (stat(FILE_NAME(channel), &statbuf) != 0 && errno == ENOENT) || statbuf.st_size < FILE_MAXSIZE(channel)) { (void)fclose(FILE_STREAM(channel)); FILE_STREAM(channel) = NULL; FILE_MAXREACHED(channel) = ISC_FALSE; } else /* * Eh, skip it. */ break; } if (FILE_STREAM(channel) == NULL) { result = isc_log_open(channel); if (result != ISC_R_SUCCESS && result != ISC_R_MAXSIZE && (channel->flags & ISC_LOG_OPENERR) == 0) { syslog(LOG_ERR, "isc_log_open '%s' failed: %s", FILE_NAME(channel), isc_result_totext(result)); channel->flags |= ISC_LOG_OPENERR; } if (result != ISC_R_SUCCESS) break; channel->flags &= ~ISC_LOG_OPENERR; } /* FALLTHROUGH */ case ISC_LOG_TOFILEDESC: fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n", printtime ? time_string : "", printtime ? " " : "", printtag ? lcfg->tag : "", printtag ? ": " : "", printcategory ? category->name : "", printcategory ? ": " : "", printmodule ? (module != NULL ? module->name : "no_module") : "", printmodule ? ": " : "", printlevel ? level_string : "", lctx->buffer); fflush(FILE_STREAM(channel)); /* * If the file now exceeds its maximum size * threshold, note it so that it will not be logged * to any more. */ if (FILE_MAXSIZE(channel) > 0) { INSIST(channel->type == ISC_LOG_TOFILE); /* XXXDCL NT fstat/fileno */ /* XXXDCL complain if fstat fails? */ if (fstat(fileno(FILE_STREAM(channel)), &statbuf) >= 0 && statbuf.st_size > FILE_MAXSIZE(channel)) FILE_MAXREACHED(channel) = ISC_TRUE; } break; case ISC_LOG_TOSYSLOG: if (level > 0) syslog_level = LOG_DEBUG; else if (level < ISC_LOG_CRITICAL) syslog_level = LOG_CRIT; else syslog_level = syslog_map[-level]; (void)syslog(FACILITY(channel) | syslog_level, "%s%s%s%s%s%s%s%s%s", printtime ? time_string : "", printtag ? lcfg->tag : "", printtag ? ": " : "", printcategory ? category->name : "", printcategory ? ": " : "", printmodule ? (module != NULL ? module->name : "no_module") : "", printmodule ? ": " : "", printlevel ? level_string : "", lctx->buffer); break; case ISC_LOG_TONULL: break; } } while (1); UNLOCK(&lctx->lock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -