From 3ffcb34e5d03791273360d031f512913228dd04f Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Fri, 8 Nov 2024 08:36:12 -0500 Subject: [PATCH] Issue 5842 - Add log buffering for error log Description: Adding log buffering for error log. Also refactored and cleaned up some of the code. relates: https://github.com/389ds/389-ds-base/issues/5842 Reviewed by: tbordaz & progier (Thanks!!) --- .../tests/suites/ds_logs/ds_logs_test.py | 38 ++ ldap/servers/slapd/libglobs.c | 21 + ldap/servers/slapd/log.c | 563 +++++++++++------- ldap/servers/slapd/log.h | 3 +- ldap/servers/slapd/proto-slap.h | 1 + ldap/servers/slapd/slap.h | 2 + 6 files changed, 401 insertions(+), 227 deletions(-) diff --git a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py index 8670db3121..209d63b5df 100644 --- a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py +++ b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py @@ -1369,9 +1369,47 @@ def fin(): log.info('Restore dse.ldif') topology_st.standalone.stop() shutil.copy(dse_ldif + '.correct', dse_ldif) + topology_st.standalone.start() request.addfinalizer(fin) + +def test_errorlog_buffering(topology_st, request): + """Test log buffering works as expected when on or off + + :id: 324ec5ed-c8ec-49fe-ab20-8c8cbfedca41 + :setup: Standalone Instance + :steps: + 1. Set buffering on + 2. Reset logs and restart the server + 3. Check for logging that should be buffered (not found) + 4. Disable buffering + 5. Reset logs and restart the server + 6. Check for logging that should be found + :expectedresults: + 1. Success + 2. Success + 3. Success + 4. Success + 5. Success + 6. Success + """ + + # Configure instance + inst = topology_st.standalone + inst.config.replace('nsslapd-errorlog-logbuffering', 'on') + inst.deleteErrorLogs(restart=True) + + time.sleep(1) + assert not inst.ds_error_log.match(".*slapd_daemon - slapd started.*") + + inst.config.replace('nsslapd-errorlog-logbuffering', 'off') + inst.deleteErrorLogs(restart=True) + + time.sleep(1) + assert inst.ds_error_log.match(".*slapd_daemon - slapd started.*") + + if __name__ == '__main__': # Run isolated # -s for DEBUG mode diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index 3eb0d9fe53..6af49a54f2 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -186,6 +186,7 @@ slapi_onoff_t init_securitylog_compress_enabled; slapi_onoff_t init_auditlog_compress_enabled; slapi_onoff_t init_auditfaillog_compress_enabled; slapi_onoff_t init_errorlog_compress_enabled; +slapi_onoff_t init_errorlogbuffering; slapi_onoff_t init_accesslog_logging_enabled; slapi_onoff_t init_accesslogbuffering; slapi_onoff_t init_securitylog_logging_enabled; @@ -848,6 +849,10 @@ static struct config_get_and_set NULL, 0, (void **)&global_slapdFrontendConfig.securitylogbuffering, CONFIG_ON_OFF, NULL, &init_securitylogbuffering, NULL}, + {CONFIG_ERRORLOG_BUFFERING_ATTRIBUTE, config_set_errorlogbuffering, + NULL, 0, + (void **)&global_slapdFrontendConfig.errorlogbuffering, + CONFIG_ON_OFF, NULL, &init_errorlogbuffering, NULL}, {CONFIG_CSNLOGGING_ATTRIBUTE, config_set_csnlogging, NULL, 0, (void **)&global_slapdFrontendConfig.csnlogging, @@ -1910,6 +1915,7 @@ FrontendConfig_init(void) cfg->errorlog_exptimeunit = slapi_ch_strdup(SLAPD_INIT_LOG_EXPTIMEUNIT); cfg->errorloglevel = SLAPD_DEFAULT_FE_ERRORLOG_LEVEL; init_errorlog_compress_enabled = cfg->errorlog_compress = LDAP_OFF; + init_errorlogbuffering = cfg->errorlogbuffering = LDAP_OFF; init_auditlog_logging_enabled = cfg->auditlog_logging_enabled = LDAP_OFF; cfg->auditlog_log_format = slapi_ch_strdup(SLAPD_INIT_AUDITLOG_LOG_FORMAT); @@ -7852,6 +7858,21 @@ config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, return retVal; } +int32_t +config_set_errorlogbuffering(const char *attrname, char *value, char *errorbuf, int apply) +{ + int32_t retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + retVal = config_set_onoff(attrname, + value, + &(slapdFrontendConfig->errorlogbuffering), + errorbuf, + apply); + + return retVal; +} + int32_t config_set_auditlogbuffering(const char *attrname, char *value, char *errorbuf, int apply) { diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c index bd6bbca338..8352f4abd3 100644 --- a/ldap/servers/slapd/log.c +++ b/ldap/servers/slapd/log.c @@ -48,6 +48,8 @@ struct logbufinfo *logbuf_accum; static struct logging_opts loginfo; static int detached = 0; +typedef int open_log(int32_t state, int32_t flags); + //extern int slapd_ldap_debug; /* @@ -121,11 +123,12 @@ static int vslapd_log_security(const char *log_data); static void log_convert_time(time_t ctime, char *tbuf, int type); static time_t log_reverse_convert_time(char *tbuf); static LogBufferInfo *log_create_buffer(size_t sz); -static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2); +static void log_append_access_buffer(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2); static void log_append_security_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size); static void log_append_audit_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size); static void log_append_auditfail_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size); -static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now); +static void log_append_error_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size, int locked); +static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now, int locked); static void log_write_title(LOGFD fp); static void log__error_emergency(const char *errstr, int reopen, int locked); static void vslapd_log_emergency_error(LOGFD fp, const char *msg, int locked); @@ -235,6 +238,8 @@ slapd_log_error_proc_internal( * LOG_WRITE_NOW(fd, buffer, size, headersize, err) writes into a LOGFD and * flushes the buffer if necessary * LOG_CLOSE(fd) closes the logfile + * + * Note - the LOG_WRITE macros set "rc" */ #define LOG_OPEN_APPEND(fd, filename, mode) \ (((fd) = PR_Open((filename), PR_WRONLY | PR_APPEND | PR_CREATE_FILE, \ @@ -243,30 +248,36 @@ slapd_log_error_proc_internal( (((fd) = PR_Open((filename), PR_WRONLY | PR_TRUNCATE | \ PR_CREATE_FILE, \ mode)) != NULL) -#define LOG_WRITE(fd, buffer, size, headersize) \ - if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ - PRErrorCode prerr = PR_GetError(); \ - syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ - } -#define LOG_WRITE_NOW(fd, buffer, size, headersize, err) \ - do { \ - (err) = 0; \ - if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ - PRErrorCode prerr = PR_GetError(); \ - syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ - (err) = prerr; \ - } \ - /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \ - PR_Sync(fd); \ +#define LOG_WRITE(fd, buffer, size, headersize) \ + if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ + PRErrorCode prerr = PR_GetError(); \ + syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", \ + prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ + rc = -1; \ + } +#define LOG_WRITE_NOW(fd, buffer, size, headersize, err) \ + do { \ + (err) = 0; \ + if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ + PRErrorCode prerr = PR_GetError(); \ + syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", \ + prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ + (err) = prerr; \ + rc = -1; \ + } \ + /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \ + PR_Sync(fd); \ } while (0) -#define LOG_WRITE_NOW_NO_ERR(fd, buffer, size, headersize) \ - do { \ - if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ - PRErrorCode prerr = PR_GetError(); \ - syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ - } \ - /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \ - PR_Sync(fd); \ +#define LOG_WRITE_NOW_NO_ERR(fd, buffer, size, headersize) \ + do { \ + if (slapi_write_buffer((fd), (buffer), (PRInt32)(size)) != (PRInt32)(size)) { \ + PRErrorCode prerr = PR_GetError(); \ + syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", \ + prerr, slapd_pr_strerror(prerr), (buffer) + (headersize)); \ + rc = -1; \ + } \ + /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \ + PR_Sync(fd); \ } while (0) #define LOG_CLOSE(fd) \ PR_Close((fd)) @@ -418,6 +429,10 @@ g_log_init() if ((loginfo.log_error_rwlock = slapi_new_rwlock()) == NULL) { exit(-1); } + loginfo.log_error_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE); + if ((loginfo.log_error_buffer->lock = PR_NewLock()) == NULL) { + exit(-1); + } /* AUDIT LOG */ loginfo.log_audit_state = cfg->auditlog_logging_enabled; @@ -2245,12 +2260,16 @@ log_write_title(LOGFD fp) char *buildnum = config_get_buildnum(); char buff[512]; int bufflen = sizeof(buff); + int rc = 0; PR_snprintf(buff, bufflen, "\t%s B%s\n", fe_cfg->versionstring ? fe_cfg->versionstring : CAPBRAND "-Directory/" DS_PACKAGE_VERSION, buildnum ? buildnum : ""); LOG_WRITE_NOW_NO_ERR(fp, buff, strlen(buff), 0); - + if (rc != 0) { + slapi_ch_free((void **)&buildnum); + return; + } if (fe_cfg->localhost) { PR_snprintf(buff, bufflen, "\t%s:%d (%s)\n\n", fe_cfg->localhost, @@ -2276,7 +2295,6 @@ log_write_title(LOGFD fp) int error_log_openf(char *pathname, int locked) { - int rv = 0; int logfile_type = 0; @@ -2314,7 +2332,6 @@ error_log_openf(char *pathname, int locked) int audit_log_openf(char *pathname, int locked) { - int rv = 0; int logfile_type = 0; @@ -2355,7 +2372,6 @@ audit_log_openf(char *pathname, int locked) int auditfail_log_openf(char *pathname, int locked) { - int rv = 0; int logfile_type = 0; @@ -2408,7 +2424,7 @@ vslapd_log_audit(const char *log_data, PRBool json_format) */ if (msg_len > SLAPI_LOG_BUFSIZ) { PR_Lock(loginfo.log_audit_buffer->lock); - log_flush_buffer(loginfo.log_audit_buffer, SLAPD_AUDIT_LOG, 0); + log_flush_buffer(loginfo.log_audit_buffer, SLAPD_AUDIT_LOG, 0, 1); LogBufferInfo lbi; lbi.top = (char *)log_data; @@ -2416,7 +2432,7 @@ vslapd_log_audit(const char *log_data, PRBool json_format) lbi.maxsize = msg_len; lbi.lock = NULL; lbi.refcount = 0; - log_flush_buffer(&lbi, SLAPD_AUDIT_LOG, 0); + log_flush_buffer(&lbi, SLAPD_AUDIT_LOG, 0, 1); PR_Unlock(loginfo.log_audit_buffer->lock); return 0; @@ -2495,7 +2511,7 @@ log_append_audit_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size) (tnl >= loginfo.log_audit_rotationsyncclock && loginfo.log_audit_rotationsync_enabled)) { - log_flush_buffer(lbi, SLAPD_AUDIT_LOG, 0 /* do not sync to disk */); + log_flush_buffer(lbi, SLAPD_AUDIT_LOG, 0 /* do not sync to disk */, 1); } insert_point = lbi->current; lbi->current += size; @@ -2512,7 +2528,7 @@ log_append_audit_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size) /* If we are asked to sync to disk immediately, do so */ if (!slapdFrontendConfig->auditlogbuffering) { PR_Lock(lbi->lock); - log_flush_buffer(lbi, SLAPD_AUDIT_LOG, 1 /* sync to disk now */); + log_flush_buffer(lbi, SLAPD_AUDIT_LOG, 1 /* sync to disk now */, 1); PR_Unlock(lbi->lock); } } @@ -2539,7 +2555,7 @@ vslapd_log_auditfail(const char *log_data, PRBool json_format) */ if (msg_len > SLAPI_LOG_BUFSIZ) { PR_Lock(loginfo.log_auditfail_buffer->lock); - log_flush_buffer(loginfo.log_auditfail_buffer, SLAPD_AUDITFAIL_LOG, 0); + log_flush_buffer(loginfo.log_auditfail_buffer, SLAPD_AUDITFAIL_LOG, 0, 1); LogBufferInfo lbi; lbi.top = (char *)log_data; @@ -2547,7 +2563,7 @@ vslapd_log_auditfail(const char *log_data, PRBool json_format) lbi.maxsize = msg_len; lbi.lock = NULL; lbi.refcount = 0; - log_flush_buffer(&lbi, SLAPD_AUDITFAIL_LOG, 0); + log_flush_buffer(&lbi, SLAPD_AUDITFAIL_LOG, 0, 1); PR_Unlock(loginfo.log_auditfail_buffer->lock); return 0; @@ -2626,7 +2642,7 @@ log_append_auditfail_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t si (tnl >= loginfo.log_auditfail_rotationsyncclock && loginfo.log_auditfail_rotationsync_enabled)) { - log_flush_buffer(lbi, SLAPD_AUDITFAIL_LOG, 0 /* do not sync to disk */); + log_flush_buffer(lbi, SLAPD_AUDITFAIL_LOG, 0 /* do not sync to disk */, 1); } insert_point = lbi->current; lbi->current += size; @@ -2643,7 +2659,7 @@ log_append_auditfail_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t si /* If we are asked to sync to disk immediately, do so */ if (!slapdFrontendConfig->auditlogbuffering) { PR_Lock(lbi->lock); - log_flush_buffer(lbi, SLAPD_AUDITFAIL_LOG, 1 /* sync to disk now */); + log_flush_buffer(lbi, SLAPD_AUDITFAIL_LOG, 1 /* sync to disk now */, 1); PR_Unlock(lbi->lock); } } @@ -2803,6 +2819,44 @@ get_log_sev_name(int loglevel, char *sev_name) return ""; } +static void +log_append_error_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t size, int locked) +{ + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + char *insert_point = NULL; + + /* While holding the lock, we determine if there is space in the buffer for our payload, + and if we need to flush. + */ + PR_Lock(lbi->lock); + if (((lbi->current - lbi->top) + size > lbi->maxsize) || + (tnl >= loginfo.log_error_rotationsyncclock && + loginfo.log_error_rotationsync_enabled)) + { + log_flush_buffer(lbi, SLAPD_ERROR_LOG, 0 /* do not sync to disk */, + locked); + } + insert_point = lbi->current; + lbi->current += size; + /* Increment the copy refcount */ + slapi_atomic_incr_64(&(lbi->refcount), __ATOMIC_RELEASE); + PR_Unlock(lbi->lock); + + /* Now we can copy without holding the lock */ + memcpy(insert_point, msg, size); + + /* Decrement the copy refcount */ + slapi_atomic_decr_64(&(lbi->refcount), __ATOMIC_RELEASE); + + /* If we are asked to sync to disk immediately, do so */ + if (!slapdFrontendConfig->errorlogbuffering) { + PR_Lock(lbi->lock); + log_flush_buffer(lbi, SLAPD_ERROR_LOG, 1 /* sync to disk now */, + locked); + PR_Unlock(lbi->lock); + } +} + static int vslapd_log_error( LOGFD fp, @@ -2812,13 +2866,12 @@ vslapd_log_error( va_list ap, int locked) { + time_t tnl = slapi_current_utc_time(); char buffer[SLAPI_LOG_BUFSIZ]; struct timespec tsnow; char sev_name[10]; int blen = TBUFSIZE; char *vbuf = NULL; - int header_len = 0; - int err = 0; if (vasprintf(&vbuf, fmt, ap) == -1) { log__error_emergency("vslapd_log_error, Unable to format message", 1, locked); @@ -2841,23 +2894,21 @@ vslapd_log_error( return -1; } - /* Bug 561525: to be able to remove timestamp to not over pollute syslog, we may need - to skip the timestamp part of the message. - The size of the header is: - the size of the time string - + size of space - + size of one char (sign) - + size of 2 char - + size of 2 char - + size of [ - + size of ] - */ - - /* Due to the change to use format_localTime_log, this is now blen */ - header_len = blen; + /* + * To be able to remove timestamp to not over pollute the syslog, we may + * need to skip the timestamp part of the message. + * + * The size of the header is: + * the size of the time string + * + size of space + * + size of one char (sign) + * + size of 2 char + * + size of 2 char + * + size of [ + * + size of ] + */ - /* blen = strlen(buffer); */ - /* This truncates again .... But we have the nice smprintf above! */ + /* This truncates again... But we have the nice smprintf from above! */ if (subsystem == NULL) { snprintf(buffer + blen, sizeof(buffer) - blen, "- %s - %s", get_log_sev_name(sev_level, sev_name), vbuf); @@ -2867,28 +2918,12 @@ vslapd_log_error( } buffer[sizeof(buffer) - 1] = '\0'; - - if (fp) - do { - int size = strlen(buffer); - (err) = 0; - if (slapi_write_buffer((fp), (buffer), (size)) != (size)) { - PRErrorCode prerr = PR_GetError(); - syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer) + (header_len)); - (err) = prerr; - } - /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ - PR_Sync(fp); - } while (0); - else /* stderr is always unbuffered */ - fprintf(stderr, "%s", buffer); - - if (err) { - PR_snprintf(buffer, sizeof(buffer), - "Writing to the errors log failed. Exiting..."); - log__error_emergency(buffer, 1, locked); - /* failed to write to the errors log. should not continue. */ - g_set_shutdown(SLAPI_SHUTDOWN_EXIT); + if (fp) { + log_append_error_buffer(tnl, loginfo.log_error_buffer, buffer, + strlen(buffer), locked); + } else { + /* stderr is always unbuffered */ + fprintf(stderr, "%s", buffer); } slapi_ch_free_string(&vbuf); @@ -3060,7 +3095,9 @@ vslapd_log_access(const char *fmt, va_list ap) * someone is trying to do something bad. */ vlen = strlen(vbuf); /* Truncated length */ memcpy(&vbuf[vlen-4], "...\n", 4); /* Replace last characters with three dots and a new line character */ - slapi_log_err(SLAPI_LOG_ERR, "vslapd_log_access", "Insufficient buffer capacity to fit timestamp and message! The line in the access log was truncated\n"); + slapi_log_err(SLAPI_LOG_ERR, "vslapd_log_access", + "Insufficient buffer capacity to fit timestamp and message! " + "The line in the access log was truncated\n"); rc = -1; } @@ -3068,7 +3105,7 @@ vslapd_log_access(const char *fmt, va_list ap) STAP_PROBE(ns-slapd, vslapd_log_access__prepared); #endif - log_append_buffer2(tnl, loginfo.log_access_buffer, buffer, blen, vbuf, vlen); + log_append_access_buffer(tnl, loginfo.log_access_buffer, buffer, blen, vbuf, vlen); #ifdef SYSTEMTAP STAP_PROBE(ns-slapd, vslapd_log_access__buffer); @@ -3191,13 +3228,13 @@ access_log_openf(char *pathname, int locked) static int log__open_accesslogfile(int logfile_state, int locked) { - time_t now; LOGFD fp; LOGFD fpinfo = NULL; char tbuf[TBUFSIZE]; struct logfileinfo *logp; char buffer[BUFSIZ]; + int rc; if (!locked) LOG_ACCESS_LOCK_WRITE(); @@ -3326,8 +3363,12 @@ log__open_accesslogfile(int logfile_state, int locked) PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%" PRId64 ")\n", PREVLOGFILE, loginfo.log_access_file, tbuf, logp->l_ctime, logp->l_size); LOG_WRITE(fpinfo, buffer, strlen(buffer), 0); + if (rc != 0) { + break; + } logp = logp->l_next; } + /* Close the info file. We need only when we need to rotate to the ** next log file. */ @@ -3351,13 +3392,13 @@ log__open_accesslogfile(int logfile_state, int locked) static int log__open_securitylogfile(int logfile_state, int locked) { - time_t now; LOGFD fp; LOGFD fpinfo = NULL; char tbuf[TBUFSIZE]; struct logfileinfo *logp; char buffer[BUFSIZ]; + int rc; if (!locked) LOG_SECURITY_LOCK_WRITE(); @@ -3490,8 +3531,12 @@ log__open_securitylogfile(int logfile_state, int locked) PREVLOGFILE, loginfo.log_security_file, tbuf, logp->l_ctime, logp->l_size); LOG_WRITE(fpinfo, buffer, strlen(buffer), 0); + if (rc != 0) { + break; + } logp = logp->l_next; } + /* Close the info file. We need only when we need to rotate to the ** next log file. */ @@ -3906,7 +3951,7 @@ log_append_security_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t siz (tnl >= loginfo.log_security_rotationsyncclock && loginfo.log_security_rotationsync_enabled)) { - log_flush_buffer(lbi, SLAPD_SECURITY_LOG, 0 /* do not sync to disk */); + log_flush_buffer(lbi, SLAPD_SECURITY_LOG, 0 /* do not sync to disk */, 1); } insert_point = lbi->current; lbi->current += size; @@ -3923,7 +3968,7 @@ log_append_security_buffer(time_t tnl, LogBufferInfo *lbi, char *msg, size_t siz /* If we are asked to sync to disk immediately, do so */ if (!slapdFrontendConfig->securitylogbuffering) { PR_Lock(lbi->lock); - log_flush_buffer(lbi, SLAPD_SECURITY_LOG, 1 /* sync to disk now */); + log_flush_buffer(lbi, SLAPD_SECURITY_LOG, 1 /* sync to disk now */, 1); PR_Unlock(lbi->lock); } } @@ -5039,7 +5084,6 @@ log__extract_logheader(FILE *fp, long *f_ctime, PRInt64 *f_size, PRBool *compres *compressed = PR_TRUE; } } - return LOG_CONTINUE; } @@ -5871,8 +5915,9 @@ log__audit_rotationinfof(char *pathname) */ while ((rval = log__extract_logheader(fp, &f_ctime, &f_size, &compressed)) == LOG_CONTINUE) { /* first we would get the main log info */ - if (f_ctime == 0 && f_size == 0) + if (f_ctime == 0 && f_size == 0) { continue; + } time(&now); if (main_log) { @@ -6054,7 +6099,6 @@ log__error_emergency(const char *errstr, int reopen, int locked) static int log__open_errorlogfile(int logfile_state, int locked) { - time_t now; LOGFD fp = NULL; LOGFD fpinfo = NULL; @@ -6185,6 +6229,7 @@ log__open_errorlogfile(int logfile_state, int locked) /* we have all the information */ if (!locked) LOG_ERROR_UNLOCK_WRITE(); + return LOG_SUCCESS; } @@ -6225,8 +6270,12 @@ log__open_errorlogfile(int logfile_state, int locked) PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%" PRId64 "d)\n", PREVLOGFILE, loginfo.log_error_file, tbuf, logp->l_ctime, logp->l_size); LOG_WRITE(fpinfo, buffer, strlen(buffer), 0); + if (rc != 0) { + break; + } logp = logp->l_next; } + /* Close the info file. We need only when we need to rotate to the ** next log file. */ @@ -6250,13 +6299,13 @@ log__open_errorlogfile(int logfile_state, int locked) static int log__open_auditlogfile(int logfile_state, int locked) { - time_t now; LOGFD fp; LOGFD fpinfo = NULL; char tbuf[TBUFSIZE]; struct logfileinfo *logp; char buffer[BUFSIZ]; + int rc; if (!locked) LOG_AUDIT_LOCK_WRITE(); @@ -6380,8 +6429,12 @@ log__open_auditlogfile(int logfile_state, int locked) PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%" PRId64 "d)\n", PREVLOGFILE, loginfo.log_audit_file, tbuf, logp->l_ctime, logp->l_size); LOG_WRITE(fpinfo, buffer, strlen(buffer), 0); + if (rc != 0) { + break; + } logp = logp->l_next; } + /* Close the info file. We need only when we need to rotate to the ** next log file. */ @@ -6395,6 +6448,7 @@ log__open_auditlogfile(int logfile_state, int locked) LOG_AUDIT_UNLOCK_WRITE(); return LOG_SUCCESS; } + /****************************************************************************** * log__open_auditfaillogfile * @@ -6404,13 +6458,13 @@ log__open_auditlogfile(int logfile_state, int locked) static int log__open_auditfaillogfile(int logfile_state, int locked) { - time_t now; LOGFD fp; LOGFD fpinfo = NULL; char tbuf[TBUFSIZE]; struct logfileinfo *logp; char buffer[BUFSIZ]; + int rc; if (!locked) LOG_AUDITFAIL_LOCK_WRITE(); @@ -6534,8 +6588,12 @@ log__open_auditfaillogfile(int logfile_state, int locked) PR_snprintf(buffer, sizeof(buffer), "LOGINFO:%s%s.%s (%lu) (%" PRId64 "d)\n", PREVLOGFILE, loginfo.log_auditfail_file, tbuf, logp->l_ctime, logp->l_size); LOG_WRITE(fpinfo, buffer, strlen(buffer), 0); + if (rc != 0) { + break; + } logp = logp->l_next; } + /* Close the info file. We need only when we need to rotate to the ** next log file. */ @@ -6586,7 +6644,7 @@ log_create_buffer(size_t sz) * systems. */ static void -log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2) +log_append_access_buffer(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2) { slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); size_t size = size1 + size2; @@ -6601,7 +6659,7 @@ log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, cha loginfo.log_access_rotationsync_enabled)) { log_flush_buffer(lbi, SLAPD_ACCESS_LOG, - 0 /* do not sync to disk right now */); + 0 /* do not sync to disk right now */, 1); } insert_point = lbi->current; lbi->current += size; @@ -6619,162 +6677,211 @@ log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, cha /* If we are asked to sync to disk immediately, do so */ if (!slapdFrontendConfig->accesslogbuffering) { PR_Lock(lbi->lock); - log_flush_buffer(lbi, SLAPD_ACCESS_LOG, 1 /* sync to disk now */); + log_flush_buffer(lbi, SLAPD_ACCESS_LOG, 1 /* sync to disk now */, 1); PR_Unlock(lbi->lock); } } +static time_t +log_update_sync_clock(int32_t log_type, int32_t secs) +{ + switch (log_type) { + case SLAPD_ACCESS_LOG: + loginfo.log_access_rotationsyncclock += PR_ABS(secs); + return loginfo.log_access_rotationsyncclock; + case SLAPD_SECURITY_LOG: + loginfo.log_security_rotationsyncclock += PR_ABS(secs); + return loginfo.log_security_rotationsyncclock; + case SLAPD_AUDIT_LOG: + loginfo.log_audit_rotationsyncclock += PR_ABS(secs); + return loginfo.log_audit_rotationsyncclock; + case SLAPD_AUDITFAIL_LOG: + loginfo.log_auditfail_rotationsyncclock += PR_ABS(secs); + return loginfo.log_auditfail_rotationsyncclock; + case SLAPD_ERROR_LOG: + loginfo.log_error_rotationsyncclock += PR_ABS(secs); + return loginfo.log_error_rotationsyncclock; + default: + return 0; + } +} + +static void +log_state_remove_need_title(int32_t log_type) +{ + switch (log_type) { + case SLAPD_ACCESS_LOG: + loginfo.log_access_state &= ~LOGGING_NEED_TITLE; + break; + case SLAPD_SECURITY_LOG: + loginfo.log_security_state &= ~LOGGING_NEED_TITLE; + break; + case SLAPD_AUDIT_LOG: + loginfo.log_audit_state &= ~LOGGING_NEED_TITLE; + break; + case SLAPD_AUDITFAIL_LOG: + loginfo.log_auditfail_state &= ~LOGGING_NEED_TITLE; + break; + case SLAPD_ERROR_LOG: + loginfo.log_error_state &= ~LOGGING_NEED_TITLE; + break; + } +} + +static int32_t +log_refresh_state(int32_t log_type) +{ + switch (log_type) { + case SLAPD_ACCESS_LOG: + return loginfo.log_access_state; + case SLAPD_SECURITY_LOG: + return loginfo.log_security_state; + case SLAPD_AUDIT_LOG: + return loginfo.log_audit_state; + case SLAPD_AUDITFAIL_LOG: + return loginfo.log_auditfail_state; + case SLAPD_ERROR_LOG: + return loginfo.log_error_state; + default: + return 0; + } +} /* this function assumes the lock is already acquired */ /* if sync_now is non-zero, data is flushed to physical storage */ static void -log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now) +log_flush_buffer(LogBufferInfo *lbi, int log_type, int sync_now, int locked) { slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + LOGFD fd; + char *log_name; + char *log_file = NULL; + time_t rotation_sync_clock; + time_t log_ctime; + int32_t rotationtime_secs; + int32_t log_state; + PRBool log_buffering = PR_FALSE; + open_log *open_log_file = NULL; + int rc = 0; - if (type == SLAPD_ACCESS_LOG) { - /* It is only safe to flush once any other threads which are copying are finished */ - while (slapi_atomic_load_64(&(lbi->refcount), __ATOMIC_ACQUIRE) > 0) { - /* It's ok to sleep for a while because we only flush every second or so */ - DS_Sleep(PR_MillisecondsToInterval(1)); - } + /* + * It is only safe to flush once all other threads which are copying are + * finished + */ + while (slapi_atomic_load_64(&(lbi->refcount), __ATOMIC_ACQUIRE) > 0) { + /* It's ok to sleep for a while because we only flush every second or so */ + DS_Sleep(PR_MillisecondsToInterval(1)); + } - if ((lbi->current - lbi->top) == 0) - return; + if ((lbi->current - lbi->top) == 0) { + return; + } - if (log__needrotation(loginfo.log_access_fdes, - SLAPD_ACCESS_LOG) == LOG_ROTATE) { - if (log__open_accesslogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) { - slapi_log_err(SLAPI_LOG_ERR, - "log_flush_buffer", "Unable to open access file:%s\n", - loginfo.log_access_file); - lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */ - return; - } - while (loginfo.log_access_rotationsyncclock <= loginfo.log_access_ctime) { - loginfo.log_access_rotationsyncclock += PR_ABS(loginfo.log_access_rotationtime_secs); - } - } + switch (log_type) { + case SLAPD_ACCESS_LOG: + open_log_file = &log__open_accesslogfile; + fd = loginfo.log_access_fdes; + log_file = loginfo.log_access_file; + rotation_sync_clock = loginfo.log_access_rotationsyncclock; + log_ctime = loginfo.log_access_ctime; + rotationtime_secs = loginfo.log_access_rotationtime_secs; + log_state = loginfo.log_access_state; + log_buffering = slapdFrontendConfig->accesslogbuffering ? PR_TRUE : PR_FALSE; + log_name = "access"; + break; - if (loginfo.log_access_state & LOGGING_NEED_TITLE) { - log_write_title(loginfo.log_access_fdes); - loginfo.log_access_state &= ~LOGGING_NEED_TITLE; - } - if (!sync_now && slapdFrontendConfig->accesslogbuffering) { - LOG_WRITE(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0); - } else { - LOG_WRITE_NOW_NO_ERR(loginfo.log_access_fdes, lbi->top, - lbi->current - lbi->top, 0); - } - lbi->current = lbi->top; - } else if (type == SLAPD_SECURITY_LOG) { - /* It is only safe to flush once any other threads which are copying are finished */ - while (slapi_atomic_load_64(&(lbi->refcount), __ATOMIC_ACQUIRE) > 0) { - /* It's ok to sleep for a while because we only flush every second or so */ - DS_Sleep(PR_MillisecondsToInterval(1)); - } + case SLAPD_SECURITY_LOG: + open_log_file = &log__open_securitylogfile; + fd = loginfo.log_security_fdes; + log_file = loginfo.log_security_file; + rotation_sync_clock = loginfo.log_security_rotationsyncclock; + log_ctime = loginfo.log_security_ctime; + rotationtime_secs = loginfo.log_security_rotationtime_secs; + log_state = loginfo.log_security_state; + log_buffering = slapdFrontendConfig->securitylogbuffering ? PR_TRUE : PR_FALSE; + log_name = "security audit"; + break; - if ((lbi->current - lbi->top) == 0) { - return; - } + case SLAPD_AUDIT_LOG: + open_log_file = &log__open_auditlogfile; + fd = loginfo.log_audit_fdes; + log_file = loginfo.log_audit_file; + rotation_sync_clock = loginfo.log_audit_rotationsyncclock; + log_ctime = loginfo.log_audit_ctime; + rotationtime_secs = loginfo.log_audit_rotationtime_secs; + log_state = loginfo.log_audit_state; + log_buffering = slapdFrontendConfig->auditlogbuffering ? PR_TRUE : PR_FALSE; + log_name = "audit"; + break; - if (log__needrotation(loginfo.log_security_fdes, SLAPD_SECURITY_LOG) == LOG_ROTATE) { - if (log__open_securitylogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) { - slapi_log_err(SLAPI_LOG_ERR, - "log_flush_buffer", "Unable to open security audit file:%s\n", - loginfo.log_security_file); - lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */ - return; - } - while (loginfo.log_security_rotationsyncclock <= loginfo.log_security_ctime) { - loginfo.log_security_rotationsyncclock += PR_ABS(loginfo.log_security_rotationtime_secs); - } - } + case SLAPD_AUDITFAIL_LOG: + open_log_file = &log__open_auditfaillogfile; + fd = loginfo.log_auditfail_fdes; + log_file = loginfo.log_auditfail_file; + rotation_sync_clock = loginfo.log_auditfail_rotationsyncclock; + log_ctime = loginfo.log_auditfail_ctime; + rotationtime_secs = loginfo.log_auditfail_rotationtime_secs; + log_state = loginfo.log_auditfail_state; + /* Audit fail log still uses the audit log buffering setting */ + log_buffering = slapdFrontendConfig->auditlogbuffering ? PR_TRUE : PR_FALSE; + log_name = "audit fail"; + break; - if (loginfo.log_security_state & LOGGING_NEED_TITLE) { - log_write_title(loginfo.log_security_fdes); - loginfo.log_security_state &= ~LOGGING_NEED_TITLE; - } + case SLAPD_ERROR_LOG: + open_log_file = &log__open_errorlogfile; + fd = loginfo.log_error_fdes; + log_file = loginfo.log_error_file; + rotation_sync_clock = loginfo.log_error_rotationsyncclock; + log_ctime = loginfo.log_error_ctime; + rotationtime_secs = loginfo.log_error_rotationtime_secs; + log_state = loginfo.log_error_state; + log_buffering = slapdFrontendConfig->errorlogbuffering ? PR_TRUE : PR_FALSE; + log_name = "error"; + break; - if (!sync_now && slapdFrontendConfig->securitylogbuffering) { - LOG_WRITE(loginfo.log_security_fdes, lbi->top, lbi->current - lbi->top, 0); - } else { - LOG_WRITE_NOW_NO_ERR(loginfo.log_security_fdes, lbi->top, - lbi->current - lbi->top, 0); - } - lbi->current = lbi->top; - } else if (type == SLAPD_AUDIT_LOG) { - /* It is only safe to flush once any other threads which are copying are finished */ - while (slapi_atomic_load_64(&(lbi->refcount), __ATOMIC_ACQUIRE) > 0) { - /* It's ok to sleep for a while because we only flush every second or so */ - DS_Sleep(PR_MillisecondsToInterval(1)); - } + default: + return; + } - if ((lbi->current - lbi->top) == 0) { + if (log__needrotation(fd, log_type) == LOG_ROTATE) { + if (open_log_file(LOGFILE_NEW, 1) != LOG_SUCCESS) { + slapi_log_err(SLAPI_LOG_ERR, + "log_flush_buffer", "Unable to open %s file: %s\n", + log_name, log_file); + /* reset counter to prevent overwriting rest of lbi struct */ + lbi->current = lbi->top; return; } - - if (log__needrotation(loginfo.log_audit_fdes, SLAPD_AUDIT_LOG) == LOG_ROTATE) { - if (log__open_auditlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) { - slapi_log_err(SLAPI_LOG_ERR, - "log_flush_buffer", "Unable to open audit file:%s\n", - loginfo.log_audit_file); - lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */ - return; - } - while (loginfo.log_audit_rotationsyncclock <= loginfo.log_audit_ctime) { - loginfo.log_audit_rotationsyncclock += PR_ABS(loginfo.log_audit_rotationtime_secs); - } - } - - if (loginfo.log_audit_state & LOGGING_NEED_TITLE) { - log_write_title(loginfo.log_audit_fdes); - loginfo.log_audit_state &= ~LOGGING_NEED_TITLE; - } - - if (!sync_now && slapdFrontendConfig->auditlogbuffering) { - LOG_WRITE(loginfo.log_audit_fdes, lbi->top, lbi->current - lbi->top, 0); - } else { - LOG_WRITE_NOW_NO_ERR(loginfo.log_audit_fdes, lbi->top, - lbi->current - lbi->top, 0); - } - lbi->current = lbi->top; - } else if (type == SLAPD_AUDITFAIL_LOG) { - /* It is only safe to flush once any other threads which are copying are finished */ - while (slapi_atomic_load_64(&(lbi->refcount), __ATOMIC_ACQUIRE) > 0) { - /* It's ok to sleep for a while because we only flush every second or so */ - DS_Sleep(PR_MillisecondsToInterval(1)); - } - - if ((lbi->current - lbi->top) == 0) { - return; + while (rotation_sync_clock <= log_ctime) { + rotation_sync_clock = log_update_sync_clock(log_type, + rotationtime_secs); } + log_state = log_refresh_state(log_type); + } - if (log__needrotation(loginfo.log_auditfail_fdes, SLAPD_AUDITFAIL_LOG) == LOG_ROTATE) { - if (log__open_auditfaillogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) { - slapi_log_err(SLAPI_LOG_ERR, - "log_flush_buffer", "Unable to open auditfail file:%s\n", - loginfo.log_audit_file); - lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */ - return; - } - while (loginfo.log_auditfail_rotationsyncclock <= loginfo.log_auditfail_ctime) { - loginfo.log_auditfail_rotationsyncclock += PR_ABS(loginfo.log_auditfail_rotationtime_secs); - } - } + if (log_state & LOGGING_NEED_TITLE) { + log_write_title(fd); + log_state_remove_need_title(log_type); + } - if (loginfo.log_auditfail_state & LOGGING_NEED_TITLE) { - log_write_title(loginfo.log_auditfail_fdes); - loginfo.log_auditfail_state &= ~LOGGING_NEED_TITLE; - } + if (!sync_now && log_buffering) { + LOG_WRITE(fd, lbi->top, lbi->current - lbi->top, 0); + } else { + LOG_WRITE_NOW_NO_ERR(fd, lbi->top, lbi->current - lbi->top, 0); + } + lbi->current = lbi->top; - if (!sync_now && slapdFrontendConfig->auditlogbuffering) { - LOG_WRITE(loginfo.log_auditfail_fdes, lbi->top, lbi->current - lbi->top, 0); - } else { - LOG_WRITE_NOW_NO_ERR(loginfo.log_auditfail_fdes, lbi->top, - lbi->current - lbi->top, 0); - } - lbi->current = lbi->top; + /* + * If we fail to write to the error log we must shutdown the server. + * The LOG_WRITE macros set "rc" + */ + if (log_type == SLAPD_ERROR_LOG && rc != 0) { + char buffer[SLAPI_LOG_BUFSIZ]; + PR_snprintf(buffer, sizeof(buffer), + "Writing to the errors log failed. Exiting..."); + log__error_emergency(buffer, 1, locked); + /* failed to write to the errors log. should not continue. */ + g_set_shutdown(SLAPI_SHUTDOWN_EXIT); } } @@ -6783,20 +6890,24 @@ logs_flush() { LOG_ACCESS_LOCK_WRITE(); log_flush_buffer(loginfo.log_access_buffer, SLAPD_ACCESS_LOG, - 1 /* sync to disk now */); + 1 /* sync to disk now */, 1 /* locked*/); LOG_ACCESS_UNLOCK_WRITE(); LOG_SECURITY_LOCK_WRITE(); log_flush_buffer(loginfo.log_security_buffer, SLAPD_SECURITY_LOG, - 1 /* sync to disk now */); + 1 /* sync to disk now */, 1 /* locked*/); LOG_SECURITY_UNLOCK_WRITE(); LOG_AUDIT_LOCK_WRITE(); log_flush_buffer(loginfo.log_audit_buffer, SLAPD_AUDIT_LOG, - 1 /* sync to disk now */); + 1 /* sync to disk now */, 1 /* locked*/); LOG_AUDIT_UNLOCK_WRITE(); LOG_AUDITFAIL_LOCK_WRITE(); log_flush_buffer(loginfo.log_auditfail_buffer, SLAPD_AUDITFAIL_LOG, - 1 /* sync to disk now */); + 1 /* sync to disk now */, 1 /* locked*/); LOG_AUDITFAIL_UNLOCK_WRITE(); + LOG_ERROR_LOCK_WRITE(); + log_flush_buffer(loginfo.log_error_buffer, SLAPD_ERROR_LOG, + 1 /* sync to disk now */, 1 /* locked*/); + LOG_ERROR_UNLOCK_WRITE(); } /* @@ -6942,5 +7053,5 @@ check_log_max_size(char *maxdiskspace_str, /************************************************************************************/ -/* E N D */ +/* E N D */ /************************************************************************************/ diff --git a/ldap/servers/slapd/log.h b/ldap/servers/slapd/log.h index d2e1d65b1e..efe8422dee 100644 --- a/ldap/servers/slapd/log.h +++ b/ldap/servers/slapd/log.h @@ -183,7 +183,8 @@ struct logging_opts time_t log_error_ctime; /* log creation time */ LogFileInfo *log_error_logchain; /* all the logs info */ char *log_errorinfo_file; /* error log rotation info file */ - Slapi_RWLock *log_error_rwlock; /* lock on error*/ + Slapi_RWLock *log_error_rwlock; /* lock on error */ + LogBufferInfo *log_error_buffer; /* buffer for error log */ /* These are audit log specific */ int log_audit_state; diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index a267637d78..a0346b41e2 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -386,6 +386,7 @@ int config_set_validate_cert_switch(const char *attrname, char *value, char *err int config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, int apply); int config_set_auditlogbuffering(const char *attrname, char *value, char *errorbuf, int apply); int config_set_securitylogbuffering(const char *attrname, char *value, char *errorbuf, int apply); +int config_set_errorlogbuffering(const char *attrname, char *value, char *errorbuf, int apply); int config_set_csnlogging(const char *attrname, char *value, char *errorbuf, int apply); int config_set_force_sasl_external(const char *attrname, char *value, char *errorbuf, int apply); int config_set_entryusn_global(const char *attrname, char *value, char *errorbuf, int apply); diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index fc81d08ea1..ff2530e577 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -2317,6 +2317,7 @@ typedef struct _slapdEntryPoints #define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering" #define CONFIG_SECURITYLOG_BUFFERING_ATTRIBUTE "nsslapd-securitylog-logbuffering" #define CONFIG_AUDITLOG_BUFFERING_ATTRIBUTE "nsslapd-auditlog-logbuffering" +#define CONFIG_ERRORLOG_BUFFERING_ATTRIBUTE "nsslapd-errorlog-logbuffering" #define CONFIG_CSNLOGGING_ATTRIBUTE "nsslapd-csnlogging" #define CONFIG_RETURN_EXACT_CASE_ATTRIBUTE "nsslapd-return-exact-case" #define CONFIG_RESULT_TWEAK_ATTRIBUTE "nsslapd-result-tweak" @@ -2578,6 +2579,7 @@ typedef struct _slapdFrontendConfig int errorloglevel; slapi_onoff_t external_libs_debug_enabled; slapi_onoff_t errorlog_compress; + slapi_onoff_t errorlogbuffering; /* AUDIT LOG */ char *auditlog; /* replication audit file */