Add the AccessLogger plugin (#854)
This commit is contained in:
parent
706fc70abc
commit
9a059aedef
|
@ -55,23 +55,23 @@ if (BUILD_DROGON_SHARED)
|
|||
VERSION ${DROGON_VERSION}
|
||||
SOVERSION ${DROGON_MAJOR_VERSION})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads)
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Rpcrt4 ws2_32)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
|
||||
# We export class to facilitate maintenance, thus if you compile
|
||||
# drogon on windows as a shared library, you will need to use
|
||||
# exact same compiler for drogon and your app.
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC /wd4251 /wd4275)
|
||||
endif()
|
||||
endif()
|
||||
if (WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Rpcrt4 ws2_32)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
|
||||
# We export class to facilitate maintenance, thus if you compile
|
||||
# drogon on windows as a shared library, you will need to use
|
||||
# exact same compiler for drogon and your app.
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC /wd4251 /wd4275)
|
||||
endif ()
|
||||
endif ()
|
||||
else (BUILD_DROGON_SHARED)
|
||||
add_library(${PROJECT_NAME} STATIC)
|
||||
endif (BUILD_DROGON_SHARED)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(${PROJECT_NAME} EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
|
||||
|
@ -197,6 +197,7 @@ set(DROGON_SOURCES
|
|||
lib/src/NotFound.cc
|
||||
lib/src/PluginsManager.cc
|
||||
lib/src/SecureSSLRedirector.cc
|
||||
lib/src/AccessLogger.cc
|
||||
lib/src/SessionManager.cc
|
||||
lib/src/StaticFileRouter.cc
|
||||
lib/src/TaskTimeoutFlag.cc
|
||||
|
@ -281,10 +282,10 @@ endif (BUILD_REDIS)
|
|||
|
||||
if (NOT Hiredis_FOUND)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
lib/src/RedisClientSkipped.cc
|
||||
lib/src/RedisResultSkipped.cc
|
||||
lib/src/RedisClientManagerSkipped.cc)
|
||||
${DROGON_SOURCES}
|
||||
lib/src/RedisClientSkipped.cc
|
||||
lib/src/RedisResultSkipped.cc
|
||||
lib/src/RedisClientManagerSkipped.cc)
|
||||
endif (NOT Hiredis_FOUND)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
|
@ -334,24 +335,24 @@ if (COZ_PROFILING)
|
|||
endif (COZ_PROFILING)
|
||||
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/ArrayParser.cc
|
||||
orm_lib/src/Criteria.cc
|
||||
orm_lib/src/DbClient.cc
|
||||
orm_lib/src/DbClientImpl.cc
|
||||
orm_lib/src/DbClientLockFree.cc
|
||||
orm_lib/src/DbConnection.cc
|
||||
orm_lib/src/Exception.cc
|
||||
orm_lib/src/Field.cc
|
||||
orm_lib/src/Result.cc
|
||||
orm_lib/src/Row.cc
|
||||
orm_lib/src/SqlBinder.cc
|
||||
orm_lib/src/TransactionImpl.cc
|
||||
orm_lib/src/RestfulController.cc)
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/ArrayParser.cc
|
||||
orm_lib/src/Criteria.cc
|
||||
orm_lib/src/DbClient.cc
|
||||
orm_lib/src/DbClientImpl.cc
|
||||
orm_lib/src/DbClientLockFree.cc
|
||||
orm_lib/src/DbConnection.cc
|
||||
orm_lib/src/Exception.cc
|
||||
orm_lib/src/Field.cc
|
||||
orm_lib/src/Result.cc
|
||||
orm_lib/src/Row.cc
|
||||
orm_lib/src/SqlBinder.cc
|
||||
orm_lib/src/TransactionImpl.cc
|
||||
orm_lib/src/RestfulController.cc)
|
||||
if (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/DbClientManager.cc)
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/DbClientManager.cc)
|
||||
else (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/DbClientManagerSkipped.cc)
|
||||
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
|
@ -512,7 +513,8 @@ install(FILES ${DROGON_UTIL_HEADERS}
|
|||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
|
||||
|
||||
set(DROGON_PLUGIN_HEADERS lib/inc/drogon/plugins/Plugin.h
|
||||
lib/inc/drogon/plugins/SecureSSLRedirector.h)
|
||||
lib/inc/drogon/plugins/SecureSSLRedirector.h
|
||||
lib/inc/drogon/plugins/AccessLogger.h)
|
||||
install(FILES ${DROGON_PLUGIN_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <drogon/MultiPart.h>
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
#include <drogon/plugins/SecureSSLRedirector.h>
|
||||
#include <drogon/plugins/AccessLogger.h>
|
||||
#include <drogon/Cookie.h>
|
||||
#include <drogon/Session.h>
|
||||
#include <drogon/IOThreadStorage.h>
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
*
|
||||
* AccessLogger.h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
#include <trantor/utils/AsyncFileLogger.h>
|
||||
#include <vector>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace plugin
|
||||
{
|
||||
/**
|
||||
* @brief This plugin is used to print all requests to the log.
|
||||
*
|
||||
* The json configuration is as follows:
|
||||
*
|
||||
* @code
|
||||
{
|
||||
"name": "drogon::plugin::AccessLogger",
|
||||
"dependencies": [],
|
||||
"config": {
|
||||
"log_path": "./",
|
||||
"log_format": "",
|
||||
"log_file": "access.log",
|
||||
"log_size_limit": 0,
|
||||
"use_local_time": true,
|
||||
"log_index": 0
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* log_format: a format string for access logging, there are several
|
||||
* placeholders that represent particular data.
|
||||
* $date: the time when the log was printed.
|
||||
* $request_date: the time when the request was created.
|
||||
* $request_path|$path: the path of the request.
|
||||
* $request_query|$query: the query string of the request.
|
||||
* $request_url|$url: the URL of the request, equals to
|
||||
* $request_path+"?"+$request_query.
|
||||
* $remote_addr: the remote address
|
||||
* $local_addr: the local address
|
||||
* $request_len|$body_bytes_received: the content length of the request.
|
||||
* $method: the HTTP method of the request.
|
||||
* $thread: the current thread number.
|
||||
* $response_len|$body_bytes_sent: the content length of the response.
|
||||
* $http_[header_name]: the header of the request.
|
||||
* $cookie_[cookie_name]: the cookie of the request.
|
||||
* $upstream_http_[header_name]: the header of the response sent to the
|
||||
* client.
|
||||
* $status_code: the status code of the response.
|
||||
* $status: the status code and string of the response.
|
||||
* $processing_time: request processing time in seconds with a microseconds
|
||||
* resolution; time elapsed between the request object was
|
||||
* created and response object was created.
|
||||
* @note If the format string is empty or not configured, a default value of
|
||||
* "$request_date $method $url [$body_bytes_received] ($remote_addr -
|
||||
* $local_addr) $status $body_bytes_sent $processing_time" is applied.
|
||||
*
|
||||
* log_path: Log file path, empty by default,in which case,logs are output to
|
||||
* the regular log file (or stdout based on the log configuration).
|
||||
*
|
||||
* log_file: The access log file name, 'access.log' by default. if the file name
|
||||
* does not contain a extension, the .log extension is used.
|
||||
*
|
||||
* log_size_limit: 0 bytes by default, when the log file size reaches
|
||||
* "log_size_limit", the log file is switched. Zero value means never switch
|
||||
*
|
||||
* log_index: The index of log output, 0 by default.
|
||||
*
|
||||
* Enable the plugin by adding the configuration to the list of plugins in the
|
||||
* configuration file.
|
||||
*
|
||||
*/
|
||||
class DROGON_EXPORT AccessLogger : public drogon::Plugin<AccessLogger>
|
||||
{
|
||||
public:
|
||||
AccessLogger()
|
||||
{
|
||||
}
|
||||
void initAndStart(const Json::Value &config) override;
|
||||
void shutdown() override;
|
||||
|
||||
private:
|
||||
trantor::AsyncFileLogger asyncFileLogger_;
|
||||
int logIndex_{0};
|
||||
bool useLocalTime_{true};
|
||||
using LogFunction = std::function<void(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &)>;
|
||||
std::vector<LogFunction> logFunctions_;
|
||||
void logging(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &resp);
|
||||
void createLogFunctions(std::string format);
|
||||
LogFunction newLogFunction(const std::string &placeholder);
|
||||
std::map<std::string, LogFunction> logFunctionMap_;
|
||||
//$request_path
|
||||
static void outputReqPath(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$request_query
|
||||
static void outputReqQuery(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$request_url
|
||||
static void outputReqURL(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$date
|
||||
void outputDate(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) const;
|
||||
//$request_date
|
||||
void outputReqDate(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) const;
|
||||
//$remote_addr
|
||||
static void outputRemoteAddr(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$local_addr
|
||||
static void outputLocalAddr(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$request_len $body_bytes_received
|
||||
static void outputReqLength(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$response_len $body_bytes_sent
|
||||
static void outputRespLength(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$method
|
||||
static void outputMethod(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$thread
|
||||
static void outputThreadNumber(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$http_[header_name]
|
||||
static void outputReqHeader(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const std::string &headerName);
|
||||
//$cookie_[cookie_name]
|
||||
static void outputReqCookie(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const std::string &cookie);
|
||||
//$upstream_http_[header_name]
|
||||
static void outputRespHeader(trantor::LogStream &stream,
|
||||
const drogon::HttpResponsePtr &resp,
|
||||
const std::string &headerName);
|
||||
//$status
|
||||
static void outputStatusString(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$status_code
|
||||
static void outputStatusCode(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$processing_time
|
||||
static void outputProcessingTime(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
//$upstream_http_content-type $upstream_http_content_type
|
||||
static void outputRespContentType(trantor::LogStream &,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &);
|
||||
};
|
||||
} // namespace plugin
|
||||
} // namespace drogon
|
|
@ -0,0 +1,436 @@
|
|||
/**
|
||||
*
|
||||
* @file AccessLogger.cc
|
||||
* @author An Tao
|
||||
*
|
||||
* Copyright 2018, An Tao. All rights reserved.
|
||||
* https://github.com/an-tao/drogon
|
||||
* Use of this source code is governed by a MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* Drogon
|
||||
*
|
||||
*/
|
||||
|
||||
#include "HttpUtils.h"
|
||||
#include <drogon/drogon.h>
|
||||
#include <drogon/plugins/AccessLogger.h>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#else
|
||||
#include <sstream>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
using namespace drogon;
|
||||
using namespace drogon::plugin;
|
||||
|
||||
void AccessLogger::initAndStart(const Json::Value &config)
|
||||
{
|
||||
useLocalTime_ = config.get("use_local_time", true).asBool();
|
||||
logFunctionMap_ = {{"$request_path", outputReqPath},
|
||||
{"$path", outputReqPath},
|
||||
{"$date",
|
||||
[this](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &resp) {
|
||||
outputDate(stream, req, resp);
|
||||
}},
|
||||
{"$request_date",
|
||||
[this](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &resp) {
|
||||
outputReqDate(stream, req, resp);
|
||||
}},
|
||||
{"$request_query", outputReqQuery},
|
||||
{"$request_url", outputReqURL},
|
||||
{"$query", outputReqQuery},
|
||||
{"$url", outputReqURL},
|
||||
{"$remote_addr", outputRemoteAddr},
|
||||
{"$local_addr", outputLocalAddr},
|
||||
{"$request_len", outputReqLength},
|
||||
{"$body_bytes_received", outputReqLength},
|
||||
{"$method", outputMethod},
|
||||
{"$thread", outputThreadNumber},
|
||||
{"$response_len", outputRespLength},
|
||||
{"$body_bytes_sent", outputRespLength},
|
||||
{"$status", outputStatusString},
|
||||
{"$status_code", outputStatusCode},
|
||||
{"$processing_time", outputProcessingTime},
|
||||
{"$upstream_http_content-type", outputRespContentType},
|
||||
{"$upstream_http_content_type", outputRespContentType}};
|
||||
auto format = config.get("log_format", "").asString();
|
||||
if (format.empty())
|
||||
{
|
||||
format =
|
||||
"$request_date $method $url [$body_bytes_received] ($remote_addr - "
|
||||
"$local_addr) $status $body_bytes_sent $processing_time";
|
||||
}
|
||||
createLogFunctions(format);
|
||||
auto logPath = config.get("log_path", "").asString();
|
||||
if (!logPath.empty())
|
||||
{
|
||||
auto fileName = config.get("log_file", "access.log").asString();
|
||||
auto extension = std::string(".log");
|
||||
auto pos = fileName.rfind('.');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
extension = fileName.substr(pos);
|
||||
fileName = fileName.substr(0, pos);
|
||||
}
|
||||
if (fileName.empty())
|
||||
{
|
||||
fileName = "access";
|
||||
}
|
||||
asyncFileLogger_.setFileName(fileName, extension, logPath);
|
||||
asyncFileLogger_.startLogging();
|
||||
logIndex_ = config.get("log_index", 0).asInt();
|
||||
trantor::Logger::setOutputFunction(
|
||||
[&](const char *msg, const uint64_t len) {
|
||||
asyncFileLogger_.output(msg, len);
|
||||
},
|
||||
[&]() { asyncFileLogger_.flush(); },
|
||||
logIndex_);
|
||||
auto sizeLimit = config.get("size_limit", 0).asUInt64();
|
||||
if (sizeLimit > 0)
|
||||
{
|
||||
asyncFileLogger_.setFileSizeLimit(sizeLimit);
|
||||
}
|
||||
}
|
||||
drogon::app().registerPreSendingAdvice(
|
||||
[this](const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &resp) {
|
||||
logging(LOG_RAW_TO(logIndex_), req, resp);
|
||||
});
|
||||
}
|
||||
|
||||
void AccessLogger::shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void AccessLogger::logging(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &resp)
|
||||
{
|
||||
for (auto &func : logFunctions_)
|
||||
{
|
||||
func(stream, req, resp);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessLogger::createLogFunctions(std::string format)
|
||||
{
|
||||
std::string rawString;
|
||||
while (!format.empty())
|
||||
{
|
||||
LOG_INFO << format;
|
||||
auto pos = format.find('$');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
rawString += format.substr(0, pos);
|
||||
|
||||
format = format.substr(pos);
|
||||
std::regex e{"^\\$[a-zA-Z0-9\\-_]+"};
|
||||
std::smatch m;
|
||||
if (std::regex_search(format, m, e))
|
||||
{
|
||||
if (!rawString.empty())
|
||||
{
|
||||
logFunctions_.emplace_back(
|
||||
[rawString](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) {
|
||||
stream << rawString;
|
||||
});
|
||||
rawString.clear();
|
||||
}
|
||||
auto placeholder = m[0];
|
||||
logFunctions_.emplace_back(newLogFunction(placeholder));
|
||||
format = m.suffix().str();
|
||||
}
|
||||
else
|
||||
{
|
||||
rawString += '$';
|
||||
format = format.substr(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rawString += format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!rawString.empty())
|
||||
{
|
||||
logFunctions_.emplace_back(
|
||||
[rawString =
|
||||
std::move(rawString)](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) {
|
||||
stream << rawString << "\n";
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
logFunctions_.emplace_back(
|
||||
[](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) { stream << "\n"; });
|
||||
}
|
||||
}
|
||||
|
||||
AccessLogger::LogFunction AccessLogger::newLogFunction(
|
||||
const std::string &placeholder)
|
||||
{
|
||||
auto iter = logFunctionMap_.find(placeholder);
|
||||
if (iter != logFunctionMap_.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
if (placeholder.find("$http_") == 0 && placeholder.size() > 6)
|
||||
{
|
||||
auto headerName = placeholder.substr(6);
|
||||
return [headerName =
|
||||
std::move(headerName)](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &) {
|
||||
outputReqHeader(stream, req, headerName);
|
||||
};
|
||||
}
|
||||
if (placeholder.find("$cookie_") == 0 && placeholder.size() > 8)
|
||||
{
|
||||
auto cookieName = placeholder.substr(8);
|
||||
return [cookieName =
|
||||
std::move(cookieName)](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &) {
|
||||
outputReqCookie(stream, req, cookieName);
|
||||
};
|
||||
}
|
||||
if (placeholder.find("$upstream_http_") == 0 && placeholder.size() > 15)
|
||||
{
|
||||
auto headerName = placeholder.substr(15);
|
||||
return [headerName = std::move(
|
||||
headerName)](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &resp) {
|
||||
outputRespHeader(stream, resp, headerName);
|
||||
};
|
||||
}
|
||||
return [placeholder](trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) {
|
||||
stream << placeholder;
|
||||
};
|
||||
}
|
||||
|
||||
void AccessLogger::outputReqPath(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->path();
|
||||
}
|
||||
|
||||
void AccessLogger::outputDate(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &) const
|
||||
{
|
||||
if (useLocalTime_)
|
||||
{
|
||||
stream << trantor::Date::now().toFormattedStringLocal(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << trantor::Date::now().toFormattedString(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessLogger::outputReqDate(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &) const
|
||||
{
|
||||
if (useLocalTime_)
|
||||
{
|
||||
stream << req->creationDate().toFormattedStringLocal(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << req->creationDate().toFormattedString(true);
|
||||
}
|
||||
}
|
||||
|
||||
//$request_query
|
||||
void AccessLogger::outputReqQuery(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->query();
|
||||
}
|
||||
//$request_url
|
||||
void AccessLogger::outputReqURL(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
auto &query = req->query();
|
||||
if (query.empty())
|
||||
{
|
||||
stream << req->path();
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << req->path() << '?' << query;
|
||||
}
|
||||
}
|
||||
|
||||
void AccessLogger::outputRemoteAddr(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->peerAddr().toIpPort();
|
||||
}
|
||||
|
||||
void AccessLogger::outputLocalAddr(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->localAddr().toIpPort();
|
||||
}
|
||||
|
||||
void AccessLogger::outputReqLength(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->body().length();
|
||||
}
|
||||
|
||||
void AccessLogger::outputRespLength(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &resp)
|
||||
{
|
||||
stream << resp->body().length();
|
||||
}
|
||||
void AccessLogger::outputMethod(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
stream << req->methodString();
|
||||
}
|
||||
|
||||
void AccessLogger::outputThreadNumber(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
#ifdef __linux__
|
||||
static thread_local pid_t threadId_{0};
|
||||
#else
|
||||
static thread_local uint64_t threadId_{0};
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
if (threadId_ == 0)
|
||||
threadId_ = static_cast<pid_t>(::syscall(SYS_gettid));
|
||||
#elif defined __FreeBSD__
|
||||
if (threadId_ == 0)
|
||||
{
|
||||
threadId_ = pthread_getthreadid_np();
|
||||
}
|
||||
#elif defined __OpenBSD__
|
||||
if (threadId_ == 0)
|
||||
{
|
||||
threadId_ = getthrid();
|
||||
}
|
||||
#elif defined _WIN32
|
||||
if (threadId_ == 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::this_thread::get_id();
|
||||
threadId_ = std::stoull(ss.str());
|
||||
}
|
||||
#else
|
||||
if (threadId_ == 0)
|
||||
{
|
||||
pthread_threadid_np(NULL, &threadId_);
|
||||
}
|
||||
#endif
|
||||
stream << threadId_;
|
||||
}
|
||||
|
||||
//$http_[header_name]
|
||||
void AccessLogger::outputReqHeader(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const std::string &headerName)
|
||||
{
|
||||
stream << headerName << ": " << req->getHeader(headerName);
|
||||
}
|
||||
|
||||
//$cookie_[cookie_name]
|
||||
void AccessLogger::outputReqCookie(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const std::string &cookie)
|
||||
{
|
||||
stream << "(cookie)" << cookie << "=" << req->getCookie(cookie);
|
||||
}
|
||||
|
||||
//$upstream_http_[header_name]
|
||||
void AccessLogger::outputRespHeader(trantor::LogStream &stream,
|
||||
const drogon::HttpResponsePtr &resp,
|
||||
const std::string &headerName)
|
||||
{
|
||||
stream << headerName << ": " << resp->getHeader(headerName);
|
||||
}
|
||||
|
||||
//$status
|
||||
void AccessLogger::outputStatusString(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &resp)
|
||||
{
|
||||
int code = resp->getStatusCode();
|
||||
stream << code << " " << statusCodeToString(code);
|
||||
}
|
||||
//$status_code
|
||||
void AccessLogger::outputStatusCode(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &resp)
|
||||
{
|
||||
stream << resp->getStatusCode();
|
||||
}
|
||||
//$processing_time
|
||||
void AccessLogger::outputProcessingTime(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &req,
|
||||
const drogon::HttpResponsePtr &)
|
||||
{
|
||||
auto start = req->creationDate();
|
||||
auto end = trantor::Date::now();
|
||||
auto duration =
|
||||
end.microSecondsSinceEpoch() - start.microSecondsSinceEpoch();
|
||||
auto seconds = static_cast<double>(duration) / 1000000.0;
|
||||
stream << seconds;
|
||||
}
|
||||
|
||||
//$upstream_http_content-type $upstream_http_content_type
|
||||
void AccessLogger::outputRespContentType(trantor::LogStream &stream,
|
||||
const drogon::HttpRequestPtr &,
|
||||
const drogon::HttpResponsePtr &resp)
|
||||
{
|
||||
auto typeStr = webContentTypeToString(resp->contentType());
|
||||
if (typeStr.empty())
|
||||
{
|
||||
stream << "content-type: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (typeStr.size() >= 2 && typeStr[typeStr.size() - 1] == '\n' &&
|
||||
typeStr[typeStr.size() - 2] == '\r')
|
||||
{
|
||||
stream << string_view{typeStr.data(), typeStr.size() - 2};
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << typeStr;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -350,7 +350,7 @@ void HttpRequestImpl::appendToBuffer(trantor::MsgBuffer *output) const
|
|||
for (auto it = cookies_.begin(); it != cookies_.end(); ++it)
|
||||
{
|
||||
output->append(it->first);
|
||||
output->append("= ");
|
||||
output->append("=");
|
||||
output->append(it->second);
|
||||
output->append(";");
|
||||
}
|
||||
|
@ -399,6 +399,11 @@ void HttpRequestImpl::addHeader(const char *start,
|
|||
++cpos;
|
||||
cookie_name = cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cpos = 0;
|
||||
while (cpos < cookie_value.length() &&
|
||||
isspace(cookie_value[cpos]))
|
||||
++cpos;
|
||||
cookie_value = cookie_value.substr(cpos);
|
||||
cookies_[std::move(cookie_name)] = std::move(cookie_value);
|
||||
}
|
||||
value = value.substr(pos + 1);
|
||||
|
@ -416,6 +421,11 @@ void HttpRequestImpl::addHeader(const char *start,
|
|||
++cpos;
|
||||
cookie_name = cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cpos = 0;
|
||||
while (cpos < cookie_value.length() &&
|
||||
isspace(cookie_value[cpos]))
|
||||
++cpos;
|
||||
cookie_value = cookie_value.substr(cpos);
|
||||
cookies_[std::move(cookie_name)] = std::move(cookie_value);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue