<commit_before>/* 
** TP LOG, full feature logging system for user, mainly for exporting to
** to other languages. C/C++ can use ndebug.h
**
** @file tplog.c
** 
** -----------------------------------------------------------------------------
** Enduro/X Middleware Platform for Distributed Transaction Processing
** Copyright (C) 2015, Mavimax, Ltd. All Rights Reserved.
** This software is released under one of the following licenses:
** GPL or Mavimax's license for commercial use.
** -----------------------------------------------------------------------------
** GPL license:
** 
** This program is free software; you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free Software
** Foundation; either version 2 of the License, or (at your option) any later
** version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License along with
** this program; if not, write to the Free Software Foundation, Inc., 59 Temple
** Place, Suite 330, Boston, MA 02111-1307 USA
**
** -----------------------------------------------------------------------------
** A commercial use license is available from Mavimax, Ltd
** <EMAIL>
** -----------------------------------------------------------------------------
*/
#include <ndrx_config.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdarg.h>

#include <ndrstandard.h>
#include <ndebug.h>
#include <nstdutil.h>
#include <sys_unix.h>
#include <userlog.h>
#include <nstd_tls.h>
#include <errno.h>

#include "atmi_tls.h"
/*---------------------------Externs------------------------------------*/
/*---------------------------Macros-------------------------------------*/
#define API_ENTRY {_Nunset_error();}
/*---------------------------Enums--------------------------------------*/
/*---------------------------Typedefs-----------------------------------*/
/*---------------------------Globals------------------------------------*/
/*---------------------------Statics------------------------------------*/
/*---------------------------Prototypes---------------------------------*/

/**
 * Close the file if only one logger is using that
 * @param p
 */
exprivate void logfile_close(FILE *p)
{
    ndrx_debug_t *fd_arr[5];
    int i;
    int cnt = 0;
    int num;
    /*API_ENTRY;  set TLS too work with out context... */
    
    if (p == stdout || p == stderr)
    {
        return; /* nothing todo. */
    }
    
    fd_arr[0] = &G_ndrx_debug;
    fd_arr[1] = &G_ubf_debug;
    fd_arr[2] = &G_tp_debug;
    num = 3;
    if (NULL!=G_nstd_tls)
    {
        fd_arr[3] = &G_nstd_tls->threadlog_tp;
        fd_arr[4] = &G_nstd_tls->requestlog_tp;
        num = 5;
    }
    
    for (i=0; i<num; i++)
    {
        if (fd_arr[i]->dbg_f_ptr == p)
        {
            cnt++;
        }
    }
    
    if (cnt<2)
    {
        NDRX_FCLOSE(p);
    }
}

/**
 * Set the thread based log file
 * TODO: Later we need a wrapper to set file from buffer.
 * @param logger logging sub-system
 * @param file full path to file (optional) if present, does compare
 * @return 
 */
exprivate int logfile_change_name(int logger, char *filename)
{
    ndrx_debug_t *l;
    int ret = EXSUCCEED;
    
    API_ENTRY; /* set TLS too */
    
    switch (logger)
    {
        case LOG_FACILITY_NDRX:
            l = &G_ndrx_debug;
            break;
        case LOG_FACILITY_UBF:
            l = &G_ubf_debug;
            break;
        case LOG_FACILITY_TP:
            l = &G_tp_debug;
            break;
        case LOG_FACILITY_TP_THREAD:
            l = &G_nstd_tls->threadlog_tp;
            break;
        case LOG_FACILITY_TP_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_tp;
            break;    
        case LOG_FACILITY_NDRX_THREAD:
            l = &G_nstd_tls->threadlog_ndrx;
            break;
        case LOG_FACILITY_NDRX_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_ndrx;
            break;
        case LOG_FACILITY_UBF_THREAD:
            l = &G_nstd_tls->threadlog_ubf;
            break;
        case LOG_FACILITY_UBF_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_ubf;
            break;
        default:
            _Nset_error_fmt(NEINVAL, "tplogfileset: Invalid logger: %d", logger);
            EXFAIL_OUT(ret);
            break;
    }
    
    if (NULL!=filename)
    {
        NDRX_LOG(log_debug, "Logger = %d change name to: [%s]", logger, filename);
        if (0==strcmp(l->filename, filename))
        {
            goto out;
        }
        else
        {
            strcpy(l->filename, filename);
        }
    }
    else
    {
        NDRX_LOG(log_debug, "Logger = %d change name to: [%s]", logger, l->filename);
    }
    
    /* name already changed no need to compare 
     * the caller must decide that.
     */
    if (l->dbg_f_ptr)
    {
        logfile_close(l->dbg_f_ptr);
    }

    /* open the file */
    if (EXEOS==l->filename[0])
    {
        /* log to stderr. */
        l->dbg_f_ptr = stderr;
    }
    else if (NULL==(l->dbg_f_ptr = NDRX_FOPEN(l->filename, "a")))
    {
        int err = errno;
        userlog("Failed to open %s: %s",l->filename, strerror(err));
        
        _Nset_error_fmt(NESYSTEM, "Failed to open %s: %s",l->filename, strerror(err));
        
        l->filename[0] = EXEOS;
        l->dbg_f_ptr = stderr;
    }
    else
    {   
        setvbuf(l->dbg_f_ptr, NULL, _IOFBF, l->buffer_size);
    }
     
out:
    NDRX_LOG(log_debug, "Logger = %d logging to: [%s]", logger, l->filename);
    return ret;
    
}

/**
 * Setup the request logging file.
 * NOTE that we need: 
 * 1. tplogsetreqfile(<buffer>, <filename> (optional, not needed if name already in buffer))
 * 2. tploggetreqfile(fname (out)) return TRUE/FALSE if we have, and string with the value of fname
 * 3. tplogclosereqfile(); close thre request logging.
 * File will be set to EX_REQLOG = <Full path to request log file>
 * @param filename file name to log to
 */
expublic void tplogsetreqfile_direct(char *filename)
{
    API_ENTRY; /* set TLS too */
    
    /* Level not set, then there was no init */
    if (EXFAIL==G_nstd_tls->requestlog_tp.level)
    {
        /* file is null, we want to copy off the settings  */
        if (NULL!=G_nstd_tls->threadlog_tp.dbg_f_ptr)
        {
            memcpy(&G_nstd_tls->requestlog_tp, 
                    &G_nstd_tls->threadlog_tp, sizeof(G_nstd_tls->threadlog_tp));
        }
        else
        {
            /* Copy from TPlog */
            memcpy(&G_nstd_tls->requestlog_tp, &G_tp_debug, sizeof(G_tp_debug));
        }
        G_nstd_tls->requestlog_tp.code = LOG_CODE_TP_REQUEST;
    }
    
    /* ok now open then file */
    logfile_change_name(LOG_FACILITY_TP_REQUEST, filename);
    
}

/**
 * Close the request file (back to other loggers)
 * @param filename
 */
expublic void tplogclosereqfile(void)
{
    /* Only if we have a TLS... */
    if (G_nstd_tls)
    {
        if (G_nstd_tls->requestlog_tp.dbg_f_ptr)
        {
            logfile_close(G_nstd_tls->requestlog_tp.dbg_f_ptr);
        }
        G_nstd_tls->requestlog_tp.filename[0] = EXEOS;
        G_nstd_tls->requestlog_tp.dbg_f_ptr = NULL;
    }
}


/**
 * Reconfigure loggers.
 * 
 * @param logger See LOG_FACILITY_*
 * @param lev 0..5 (if -1 (FAIL) then ignored)
 * @param config_line ndrx config line (if NULL/empty then ignored)
 * @param module 4 char module code (which uses the logger)
 * @param new_file New logging file (this overrides the stuff from debug string)
 * @return SUCCEED/FAIL
 */
expublic int tplogconfig(int logger, int lev, char *debug_string, char *module, 
        char *new_file)
{
    int ret = EXSUCCEED;
    ndrx_debug_t *l;
    char tmp_filename[PATH_MAX];
    int loggers[] = {LOG_FACILITY_NDRX, 
                    LOG_FACILITY_UBF, 
                    LOG_FACILITY_TP,
                    LOG_FACILITY_TP_THREAD,
                    LOG_FACILITY_TP_REQUEST,
                    LOG_FACILITY_NDRX_THREAD,
                    LOG_FACILITY_NDRX_REQUEST,
                    LOG_FACILITY_UBF_THREAD,
                    LOG_FACILITY_UBF_REQUEST    
    };
    int i;
    
    API_ENTRY; /* set TLS too */
    NDRX_DBG_INIT_ENTRY; /* Do the debug entry (so that we load defaults...) */
    
    for (i=0; i<N_DIM(loggers); i++)
    {
        if (loggers[i] == LOG_FACILITY_NDRX && (logger & LOG_FACILITY_NDRX))
        {
            l = &G_ndrx_debug;
        }
        else if (loggers[i] == LOG_FACILITY_UBF && (logger & LOG_FACILITY_UBF))
        {
            l = &G_ubf_debug;
        }
        else if (loggers[i] == LOG_FACILITY_TP && (logger & LOG_FACILITY_TP))
        {
            l = &G_tp_debug;
        }
        else if (loggers[i] == LOG_FACILITY_TP_THREAD && (logger & LOG_FACILITY_TP_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_tp.level)
            {
                memcpy(&G_nstd_tls->threadlog_tp, &G_tp_debug, sizeof(G_tp_debug));
                G_nstd_tls->threadlog_tp.code = LOG_CODE_TP_THREAD;
            }
            l = &G_nstd_tls->threadlog_tp;
        }
        else if (loggers[i] == LOG_FACILITY_TP_REQUEST && logger & (LOG_FACILITY_TP_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_tp.level)
            {
                memcpy(&G_nstd_tls->requestlog_tp, &G_tp_debug, sizeof(G_tp_debug));
                G_nstd_tls->requestlog_tp.code = LOG_CODE_TP_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_tp;
        }
        else if (loggers[i] == LOG_FACILITY_NDRX_THREAD && (logger & LOG_FACILITY_NDRX_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_ndrx.level)
            {
                memcpy(&G_nstd_tls->threadlog_ndrx, &G_ndrx_debug, sizeof(G_ndrx_debug));
                G_nstd_tls->threadlog_ndrx.code = LOG_CODE_NDRX_REQUEST;
            }
            l = &G_nstd_tls->threadlog_ndrx;
        }
        else if (loggers[i] == LOG_FACILITY_NDRX_REQUEST && logger & (LOG_FACILITY_NDRX_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_ndrx.level)
            {
                memcpy(&G_nstd_tls->requestlog_ndrx, &G_ndrx_debug, sizeof(G_ndrx_debug));
                G_nstd_tls->requestlog_ndrx.code = LOG_CODE_NDRX_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_ndrx;
        }
        else if (loggers[i] == LOG_FACILITY_UBF_THREAD && (logger & LOG_FACILITY_UBF_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_ubf.level)
            {
                memcpy(&G_nstd_tls->threadlog_ubf, &G_ubf_debug, sizeof(G_ubf_debug));
                G_nstd_tls->threadlog_ubf.code = LOG_CODE_NDRX_REQUEST;
            }
            l = &G_nstd_tls->threadlog_ubf;
        }
        else if (loggers[i] == LOG_FACILITY_UBF_REQUEST && logger & (LOG_FACILITY_UBF_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_ubf.level)
            {
                memcpy(&G_nstd_tls->requestlog_ubf, &G_ubf_debug, sizeof(G_ubf_debug));
                G_nstd_tls->requestlog_ubf.code = LOG_CODE_UBF_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_ubf;
        }
        else
        {
            /*
            _Nset_error_fmt(NEINVAL, "tplogconfig: Invalid logger: %d", logger);
            FAIL_OUT(ret);
             */
            continue;
        }

        if (NULL!=module && EXEOS!=module[0] && 
                loggers[i] != LOG_FACILITY_NDRX &&
                loggers[i] != LOG_FACILITY_UBF &&
                loggers[i] != LOG_FACILITY_NDRX_THREAD &&
                loggers[i] != LOG_FACILITY_UBF_THREAD &&
                loggers[i] != LOG_FACILITY_NDRX_REQUEST &&
                loggers[i] != LOG_FACILITY_UBF_REQUEST
            )
        {
            strncpy(l->module, module, 4);
            l->module[4] = EXEOS;
        }

        if (NULL!= debug_string && EXEOS!=debug_string[0])
        {
            /* parse out the logger 
             * Check if file is changed? If changed, then we shall
             * close the old file & open newone...
             */
            NDRX_STRCPY_SAFE(tmp_filename, l->filename);
            if (EXSUCCEED!= (ret = ndrx_init_parse_line(NULL, debug_string, NULL, l)))
            {
                _Nset_error_msg(NEFORMAT, "Failed to parse debug string");
                EXFAIL_OUT(ret);
            }

            /* only if new name is not passed in */
            if (0!=strcmp(tmp_filename, l->filename) && 
                    (NULL==new_file || EXEOS==new_file[0]))
            {
                /* open new log file... (to what ever level we run...) */
                if (EXSUCCEED!=(ret = logfile_change_name(loggers[i], NULL)))
                {
                    _Nset_error_msg(NESYSTEM, "Failed to change log name");
                    EXFAIL_OUT(ret);
                }
            }
        }

        if (EXFAIL!=lev)
        {
            l->level = lev;
        }
        
        /* new file passed in: */
        if (NULL!=new_file && EXEOS!=new_file[0] && 0!=strcmp(new_file, l->filename))
        {            
            /* open new log file... (to what ever level we run...) */
            strcpy(l->filename, new_file);
            if (EXSUCCEED!=(ret = logfile_change_name(loggers[i], NULL)))
            {
                _Nset_error_msg(NESYSTEM, "Failed to change log name");
                EXFAIL_OUT(ret);
            }
        }
<commit_msg>Fixes for logger file swtching - in some cenarios might cause core dump<commit_after>/* 
** TP LOG, full feature logging system for user, mainly for exporting to
** to other languages. C/C++ can use ndebug.h
**
** @file tplog.c
** 
** -----------------------------------------------------------------------------
** Enduro/X Middleware Platform for Distributed Transaction Processing
** Copyright (C) 2015, Mavimax, Ltd. All Rights Reserved.
** This software is released under one of the following licenses:
** GPL or Mavimax's license for commercial use.
** -----------------------------------------------------------------------------
** GPL license:
** 
** This program is free software; you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free Software
** Foundation; either version 2 of the License, or (at your option) any later
** version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License along with
** this program; if not, write to the Free Software Foundation, Inc., 59 Temple
** Place, Suite 330, Boston, MA 02111-1307 USA
**
** -----------------------------------------------------------------------------
** A commercial use license is available from Mavimax, Ltd
** <EMAIL>
** -----------------------------------------------------------------------------
*/
#include <ndrx_config.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdarg.h>

#include <ndrstandard.h>
#include <ndebug.h>
#include <nstdutil.h>
#include <sys_unix.h>
#include <userlog.h>
#include <nstd_tls.h>
#include <errno.h>

#include "atmi_tls.h"
/*---------------------------Externs------------------------------------*/
/*---------------------------Macros-------------------------------------*/
#define API_ENTRY {_Nunset_error();}
/*---------------------------Enums--------------------------------------*/
/*---------------------------Typedefs-----------------------------------*/
/*---------------------------Globals------------------------------------*/
/*---------------------------Statics------------------------------------*/
/*---------------------------Prototypes---------------------------------*/

/**
 * Close the file if only one logger is using that
 * @param p
 */
exprivate void logfile_close(FILE *p)
{
    ndrx_debug_t *fd_arr[9];
    int i;
    int cnt = 0;
    int num;
    /*API_ENTRY;  set TLS too work with out context... */
    
    if (p == stdout || p == stderr)
    {
        return; /* nothing todo. */
    }
    
    fd_arr[0] = &G_ndrx_debug;
    fd_arr[1] = &G_ubf_debug;
    fd_arr[2] = &G_tp_debug;
    num = 3;
    if (NULL!=G_nstd_tls)
    {
        fd_arr[3] = &G_nstd_tls->threadlog_tp;
        fd_arr[4] = &G_nstd_tls->requestlog_tp;
        
        
        fd_arr[5] = &G_nstd_tls->threadlog_ndrx;
        fd_arr[6] = &G_nstd_tls->requestlog_ndrx;
        
        fd_arr[7] = &G_nstd_tls->threadlog_ubf;
        fd_arr[8] = &G_nstd_tls->requestlog_ubf;
        
        num = 9;
    }
    
    for (i=0; i<num; i++)
    {
        if (fd_arr[i]->dbg_f_ptr == p)
        {
            cnt++;
        }
    }
    
    if (cnt<2)
    {
        NDRX_FCLOSE(p);
    }
}

/**
 * Set the thread based log file
 * TODO: Later we need a wrapper to set file from buffer.
 * @param logger logging sub-system
 * @param file full path to file (optional) if present, does compare
 * @return 
 */
exprivate int logfile_change_name(int logger, char *filename)
{
    ndrx_debug_t *l;
    int ret = EXSUCCEED;
    
    API_ENTRY; /* set TLS too */
    
    switch (logger)
    {
        case LOG_FACILITY_NDRX:
            l = &G_ndrx_debug;
            break;
        case LOG_FACILITY_UBF:
            l = &G_ubf_debug;
            break;
        case LOG_FACILITY_TP:
            l = &G_tp_debug;
            break;
        case LOG_FACILITY_TP_THREAD:
            l = &G_nstd_tls->threadlog_tp;
            break;
        case LOG_FACILITY_TP_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_tp;
            break;    
        case LOG_FACILITY_NDRX_THREAD:
            l = &G_nstd_tls->threadlog_ndrx;
            break;
        case LOG_FACILITY_NDRX_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_ndrx;
            break;
        case LOG_FACILITY_UBF_THREAD:
            l = &G_nstd_tls->threadlog_ubf;
            break;
        case LOG_FACILITY_UBF_REQUEST:
            /* set request file shall do th thread init/init level.. */
            l = &G_nstd_tls->requestlog_ubf;
            break;
        default:
            _Nset_error_fmt(NEINVAL, "tplogfileset: Invalid logger: %d", logger);
            EXFAIL_OUT(ret);
            break;
    }
    
    if (NULL!=filename)
    {
        NDRX_LOG(log_debug, "Logger = %d change name to: [%s]", logger, filename);
        if (0==strcmp(l->filename, filename))
        {
            goto out;
        }
        else
        {
            NDRX_STRCPY_SAFE(l->filename, filename);
        }
    }
    else
    {
        NDRX_LOG(log_debug, "Logger = %d change name to: [%s]", logger, l->filename);
    }
    
    /* name already changed no need to compare 
     * the caller must decide that.
     */
    if (l->dbg_f_ptr)
    {
        logfile_close(l->dbg_f_ptr);
    }

    /* open the file */
    if (EXEOS==l->filename[0])
    {
        /* log to stderr. */
        l->dbg_f_ptr = stderr;
    }
    else if (NULL==(l->dbg_f_ptr = NDRX_FOPEN(l->filename, "a")))
    {
        int err = errno;
        userlog("Failed to open %s: %s",l->filename, strerror(err));
        
        _Nset_error_fmt(NESYSTEM, "Failed to open %s: %s",l->filename, strerror(err));
        
        l->filename[0] = EXEOS;
        l->dbg_f_ptr = stderr;
    }
    else
    {   
        setvbuf(l->dbg_f_ptr, NULL, _IOFBF, l->buffer_size);
    }
     
out:
    NDRX_LOG(log_debug, "Logger = %d logging to: [%s]", logger, l->filename);
    return ret;
    
}

/**
 * Setup the request logging file.
 * NOTE that we need: 
 * 1. tplogsetreqfile(<buffer>, <filename> (optional, not needed if name already in buffer))
 * 2. tploggetreqfile(fname (out)) return TRUE/FALSE if we have, and string with the value of fname
 * 3. tplogclosereqfile(); close thre request logging.
 * File will be set to EX_REQLOG = <Full path to request log file>
 * @param filename file name to log to
 */
expublic void tplogsetreqfile_direct(char *filename)
{
    API_ENTRY; /* set TLS too */
    
    /* Level not set, then there was no init */
    if (EXFAIL==G_nstd_tls->requestlog_tp.level)
    {
        /* file is null, we want to copy off the settings  */
        if (NULL!=G_nstd_tls->threadlog_tp.dbg_f_ptr)
        {
            memcpy(&G_nstd_tls->requestlog_tp, 
                    &G_nstd_tls->threadlog_tp, sizeof(G_nstd_tls->threadlog_tp));
        }
        else
        {
            /* Copy from TPlog */
            memcpy(&G_nstd_tls->requestlog_tp, &G_tp_debug, sizeof(G_tp_debug));
        }
        G_nstd_tls->requestlog_tp.code = LOG_CODE_TP_REQUEST;
    }
    
    /* ok now open then file */
    logfile_change_name(LOG_FACILITY_TP_REQUEST, filename);
    
}

/**
 * Close the request file (back to other loggers)
 * @param filename
 */
expublic void tplogclosereqfile(void)
{
    /* Only if we have a TLS... */
    if (G_nstd_tls)
    {
        if (G_nstd_tls->requestlog_tp.dbg_f_ptr)
        {
            logfile_close(G_nstd_tls->requestlog_tp.dbg_f_ptr);
        }
        G_nstd_tls->requestlog_tp.filename[0] = EXEOS;
        G_nstd_tls->requestlog_tp.dbg_f_ptr = NULL;
    }
}


/**
 * Reconfigure loggers.
 * 
 * @param logger See LOG_FACILITY_*
 * @param lev 0..5 (if -1 (FAIL) then ignored)
 * @param config_line ndrx config line (if NULL/empty then ignored)
 * @param module 4 char module code (which uses the logger)
 * @param new_file New logging file (this overrides the stuff from debug string)
 * @return SUCCEED/FAIL
 */
expublic int tplogconfig(int logger, int lev, char *debug_string, char *module, 
        char *new_file)
{
    int ret = EXSUCCEED;
    ndrx_debug_t *l;
    char tmp_filename[PATH_MAX];
    int loggers[] = {LOG_FACILITY_NDRX, 
                    LOG_FACILITY_UBF, 
                    LOG_FACILITY_TP,
                    LOG_FACILITY_TP_THREAD,
                    LOG_FACILITY_TP_REQUEST,
                    LOG_FACILITY_NDRX_THREAD,
                    LOG_FACILITY_NDRX_REQUEST,
                    LOG_FACILITY_UBF_THREAD,
                    LOG_FACILITY_UBF_REQUEST    
    };
    int i;
    
    API_ENTRY; /* set TLS too */
    NDRX_DBG_INIT_ENTRY; /* Do the debug entry (so that we load defaults...) */
    
    for (i=0; i<N_DIM(loggers); i++)
    {
        if (loggers[i] == LOG_FACILITY_NDRX && (logger & LOG_FACILITY_NDRX))
        {
            l = &G_ndrx_debug;
        }
        else if (loggers[i] == LOG_FACILITY_UBF && (logger & LOG_FACILITY_UBF))
        {
            l = &G_ubf_debug;
        }
        else if (loggers[i] == LOG_FACILITY_TP && (logger & LOG_FACILITY_TP))
        {
            l = &G_tp_debug;
        }
        else if (loggers[i] == LOG_FACILITY_TP_THREAD && (logger & LOG_FACILITY_TP_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_tp.level)
            {
                memcpy(&G_nstd_tls->threadlog_tp, &G_tp_debug, sizeof(G_tp_debug));
                G_nstd_tls->threadlog_tp.code = LOG_CODE_TP_THREAD;
            }
            l = &G_nstd_tls->threadlog_tp;
        }
        else if (loggers[i] == LOG_FACILITY_TP_REQUEST && logger & (LOG_FACILITY_TP_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_tp.level)
            {
                memcpy(&G_nstd_tls->requestlog_tp, &G_tp_debug, sizeof(G_tp_debug));
                G_nstd_tls->requestlog_tp.code = LOG_CODE_TP_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_tp;
        }
        else if (loggers[i] == LOG_FACILITY_NDRX_THREAD && (logger & LOG_FACILITY_NDRX_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_ndrx.level)
            {
                memcpy(&G_nstd_tls->threadlog_ndrx, &G_ndrx_debug, sizeof(G_ndrx_debug));
                G_nstd_tls->threadlog_ndrx.code = LOG_CODE_NDRX_REQUEST;
            }
            l = &G_nstd_tls->threadlog_ndrx;
        }
        else if (loggers[i] == LOG_FACILITY_NDRX_REQUEST && logger & (LOG_FACILITY_NDRX_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_ndrx.level)
            {
                memcpy(&G_nstd_tls->requestlog_ndrx, &G_ndrx_debug, sizeof(G_ndrx_debug));
                G_nstd_tls->requestlog_ndrx.code = LOG_CODE_NDRX_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_ndrx;
        }
        else if (loggers[i] == LOG_FACILITY_UBF_THREAD && (logger & LOG_FACILITY_UBF_THREAD))
        {
            /* if thread was not set, then inherit the all stuff from tp
             */
            if (EXFAIL==G_nstd_tls->threadlog_ubf.level)
            {
                memcpy(&G_nstd_tls->threadlog_ubf, &G_ubf_debug, sizeof(G_ubf_debug));
                G_nstd_tls->threadlog_ubf.code = LOG_CODE_NDRX_REQUEST;
            }
            l = &G_nstd_tls->threadlog_ubf;
        }
        else if (loggers[i] == LOG_FACILITY_UBF_REQUEST && logger & (LOG_FACILITY_UBF_REQUEST))
        {
            if (EXFAIL==G_nstd_tls->requestlog_ubf.level)
            {
                memcpy(&G_nstd_tls->requestlog_ubf, &G_ubf_debug, sizeof(G_ubf_debug));
                G_nstd_tls->requestlog_ubf.code = LOG_CODE_UBF_REQUEST;
            }
            
            l = &G_nstd_tls->requestlog_ubf;
        }
        else
        {
            /*
            _Nset_error_fmt(NEINVAL, "tplogconfig: Invalid logger: %d", logger);
            FAIL_OUT(ret);
             */
            continue;
        }

        if (NULL!=module && EXEOS!=module[0] && 
                loggers[i] != LOG_FACILITY_NDRX &&
                loggers[i] != LOG_FACILITY_UBF &&
                loggers[i] != LOG_FACILITY_NDRX_THREAD &&
                loggers[i] != LOG_FACILITY_UBF_THREAD &&
                loggers[i] != LOG_FACILITY_NDRX_REQUEST &&
                loggers[i] != LOG_FACILITY_UBF_REQUEST
            )
        {
            strncpy(l->module, module, 4);
            l->module[4] = EXEOS;
        }

        if (NULL!= debug_string && EXEOS!=debug_string[0])
        {
            /* parse out the logger 
             * Check if file is changed? If changed, then we shall
             * close the old file & open newone...
             */
            NDRX_STRCPY_SAFE(tmp_filename, l->filename);
            if (EXSUCCEED!= (ret = ndrx_init_parse_line(NULL, debug_string, NULL, l)))
            {
                _Nset_error_msg(NEFORMAT, "Failed to parse debug string");
                EXFAIL_OUT(ret);
            }

            /* only if new name is not passed in */
            if (0!=strcmp(tmp_filename, l->filename) && 
                    (NULL==new_file || EXEOS==new_file[0]))
            {
                /* open new log file... (to what ever level we run...) */
                if (EXSUCCEED!=(ret = logfile_change_name(loggers[i], NULL)))
                {
                    _Nset_error_msg(NESYSTEM, "Failed to change log name");
                    EXFAIL_OUT(ret);
                }
            }
        }

        if (EXFAIL!=lev)
        {
            l->level = lev;
        }
        
        /* new file passed in: */
        if (NULL!=new_file && EXEOS!=new_file[0] && 0!=strcmp(new_file, l->filename))
        {            
            /* open new log file... (to what ever level we run...) */
            NDRX_STRCPY_SAFE(l->filename, new_file);
            if (EXSUCCEED!=(ret = logfile_change_name(loggers[i], NULL)))
            {
                _Nset_error_msg(NESYSTEM, "Failed to change log name");
                EXFAIL_OUT(ret);
            }
        }

{'fraction_non_alphanumeric': 0.15803577643210134, 'fraction_numerical': 0.003619405582237071, 'mean_word_length': 1.6621271076523996, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 181, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6109567', 'n_tokens_mistral': 9388, 'n_tokens_neox': 9211, 'n_words': 2097}