/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IHS_HOOKS_H
#define IHS_HOOKS_H

#include "ap_config.h"
#include "apr_time.h"

#ifdef __cplusplus
extern "C" {
#endif

#define REQUEST_ENVVAR "RH" /* RH stands for "request handler" */

#define HANDLER_TIME_ENVVAR "TRH"
#define CHECKUSER_TIME_ENVVAR "TCU"
#define TRANSLATENAME_TIME_ENVVAR "TTN"
#define CHECKACCESS_TIME_ENVVAR "TCA"
#define FIXUPS_TIME_ENVVAR "TFU"
#define AUTHCHECKER_TIME_ENVVAR "TAC"
#define POSTREADREQUEST_TIME_ENVVAR "TPR"
#define MAPTOSTORAGE_TIME_ENVVAR "TMS"

AP_DECLARE_DATA extern int ap_mpmstats_trackhooks;
AP_DECLARE_DATA extern int ap_mpmstats_trackhooks_loglevel;
AP_DECLARE_DATA extern apr_interval_time_t ap_mpmstats_slow_threshold;

typedef enum {
    HOOK_HANDLER = 1,
    HOOK_POST_READ_REQUEST = 2,
    HOOK_CHECK_USERID = 4,
    HOOK_CHECK_ACCESS = 8,
    HOOK_AUTH_CHECKER = 16,
    HOOK_USE_MSEC= 32,
    HOOK_LOG_THRESHOLD = 64,
    HOOK_LOG_PERMODULE = 128,
    HOOK_FIXUPS = 256,
    HOOK_TRANSLATE_NAME = 512,
    HOOK_MAPTOSTORAGE= 1024
} hook_type;

#define MPMSTATS_ENTER(hookname, isinner, beginend)                             \
    if ( (ap_mpmstats_trackhooks & hookname) &&                                 \
         ( (isinner && ap_mpmstats_trackhooks & HOOK_LOG_PERMODULE) ||          \
           (!isinner && !(ap_mpmstats_trackhooks & HOOK_LOG_PERMODULE))         \
        )){                                                                     \
        if (ap_mpmstats_trackhooks & HOOK_USE_MSEC) {        \
            beginend.usec = apr_time_now();                  \
        }                                                    \
        else {                                               \
            beginend.seconds = time(NULL);                   \
        }                                                    \
    }

#define MPMSTATS_LEAVE(r, hookname, isinner, envarname, hookstring)                             \
    if (ap_mpmstats_trackhooks & hookname && !(ap_mpmstats_trackhooks & HOOK_LOG_PERMODULE)) {  \
        apr_interval_time_t delta;                                                              \
        if (ap_mpmstats_trackhooks & HOOK_USE_MSEC) {                                           \
            end.usec = apr_time_now();                                                          \
        }                                                                                       \
        else {                                                                                  \
            end.seconds = time(NULL);                                                           \
        }                                                                                       \
        delta = mpmstats_timer_delta(begin, end);                                   \
        if (!ws->is_websockets && delta >= ap_mpmstats_slow_threshold &&            \
            (ap_mpmstats_trackhooks & HOOK_LOG_THRESHOLD)) {                        \
            ap_log_rerror(APLOG_MARK, ap_mpmstats_trackhooks_loglevel, 0, r,                        \
                          IHSLOGNO(00024) "module %s took %" APR_TIME_T_FMT                         \
                          "ms to return %s (URI %s) in phase " #hookstring,           \
                          modnames[hookstring##_modindexes[n]],                     \
                          apr_time_as_msec(delta), hookret_printable(r,rv), r->uri); \
        }                                                                           \
    }                                                                                           \
    if (ap_mpmstats_trackhooks & hookname) {                                                    \
      if (time_msg == NULL) {                                                                   \
        if (ap_mpmstats_trackhooks & HOOK_USE_MSEC) {                                           \
            time_msg = apr_psprintf(r->pool, "%" APR_TIME_T_FMT "ms",                           \
                    apr_time_as_msec(end.usec - begin.usec));                                   \
        }                                                                                       \
        else {                                                                                  \
            time_msg = apr_psprintf(r->pool, "%ld", end.seconds - begin.seconds);               \
        }                                                                                       \
      }                                                                                         \
      apr_table_set(r->subprocess_env, envarname , time_msg);                                   \
    }                                                                                           

#define MPMSTATS_LEAVE_INNER(r, hookname, hookstring)                                   \
        if (ap_mpmstats_trackhooks & hookname &&                                        \
            ap_mpmstats_trackhooks & HOOK_LOG_PERMODULE) {                              \
            char *logme = NULL;                                                         \
            apr_interval_time_t delta;                                                  \
            if (ap_mpmstats_trackhooks & HOOK_USE_MSEC) {                               \
                end.usec = apr_time_now();                                              \
                logme = apr_psprintf(r->pool, "%" APR_TIME_T_FMT "ms",                  \
                        apr_time_as_msec(end.usec - begin.usec));                       \
            }                                                                           \
            else {                                                                      \
                end.seconds = time(NULL);                                               \
                logme = apr_psprintf(r->pool, "%ld", end.seconds - begin.seconds);      \
            }                                                                           \
            delta = mpmstats_timer_delta(begin, end);                                   \
            if (delta >= APR_USEC_PER_SEC ||                                            \
                ((ap_mpmstats_trackhooks & HOOK_USE_MSEC) && delta > 1000))             \
                time_msg = apr_psprintf(r->pool, "%s%s%s:%s",                           \
                                    time_msg ? time_msg : "",                           \
                                    time_msg ? "," : "",                                \
                                    modnames[hookstring##_modindexes[n]],               \
                                    logme);                                             \
            if (!ws->is_websockets && delta >= ap_mpmstats_slow_threshold &&            \
                (ap_mpmstats_trackhooks & HOOK_LOG_THRESHOLD)) {                        \
                ap_log_rerror(APLOG_MARK, ap_mpmstats_trackhooks_loglevel, 0, r,                             \
                              IHSLOGNO(00024) "module %s took %" APR_TIME_T_FMT                         \
                              "ms to return %s (URI %s) in phase " #hookstring,           \
                              modnames[hookstring##_modindexes[n]],                     \
                              apr_time_as_msec(delta), hookret_printable(r,rv), r->uri); \
            }                                                                           \
        }
#ifdef __cplusplus
}
#endif

#endif	/* !IHS_HOOKS_H*/
