Add console logger to replace original debug output.

master
Adam Gu 7 years ago
parent bcfb1e4c92
commit 662b7c4112

@ -1,11 +1,16 @@
cmake_minimum_required(VERSION 3.1.0)
project(webcc)
option(WEBCC_ENABLE_LOG "Enable console logger?" ON)
option(WEBCC_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON)
option(WEBCC_BUILD_UNITTEST "Build unit test?" ON)
option(WEBCC_BUILD_REST_EXAMPLE "Build REST example?" ON)
option(WEBCC_BUILD_SOAP_EXAMPLE "Build SOAP example?" ON)
if(WEBCC_ENABLE_LOG)
add_definitions(-DWEBCC_ENABLE_LOG)
endif()
if(WEBCC_ENABLE_SOAP)
add_definitions(-DWEBCC_ENABLE_SOAP)
endif()

@ -3,6 +3,7 @@
#include "boost/algorithm/string.hpp"
#include "json/json.h" // jsoncpp
#include "webcc/logger.h"
#include "webcc/http_client.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
@ -54,7 +55,7 @@ public:
return false;
}
std::cout << http_response.content() << std::endl;
std::cout << "result:\n" << http_response.content() << std::endl;
return true;
}
@ -174,6 +175,8 @@ int main(int argc, char* argv[]) {
return 1;
}
LOG_INIT(webcc::VERB, 0);
g_host = argv[1];
g_port = argv[2];

@ -1,5 +1,8 @@
#include <iostream>
#include "webcc/logger.h"
#include "webcc/rest_server.h"
#include "book_services.h"
static void Help(const char* argv0) {
@ -14,6 +17,8 @@ int main(int argc, char* argv[]) {
return 1;
}
LOG_INIT(webcc::VERB, 0);
unsigned short port = std::atoi(argv[1]);
std::size_t workers = 2;

@ -1,9 +1,3 @@
option(WEBCC_DEBUG_OUTPUT "Enable debug output?" OFF)
if(WEBCC_DEBUG_OUTPUT)
add_definitions(-DWEBCC_DEBUG_OUTPUT)
endif()
# Don't use any deprecated definitions (e.g., io_service).
add_definitions(-DBOOST_ASIO_NO_DEPRECATED)
@ -30,6 +24,8 @@ set(SRCS
http_server.h
http_session.cc
http_session.h
logger.cc
logger.h
queue.h
rest_server.cc
rest_server.h

@ -64,16 +64,6 @@ const std::string kHttpPatch = "PATCH";
const std::string kHttpPut = "PUT";
const std::string kHttpDelete = "DELETE";
//enum class HttpMethod : int {
// kUnknown,
// kHead,
// kGet,
// kPost,
// kPatch,
// kPut,
// kDelete,
//};
// HTTP response status.
// This is not a full list.
// Full list: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

@ -1,9 +1,5 @@
#include "webcc/http_client.h"
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#if 0
#include "boost/asio.hpp"
#else
@ -13,6 +9,7 @@
#include "boost/asio/write.hpp"
#endif
#include "webcc/logger.h"
#include "webcc/http_response_parser.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
@ -69,9 +66,14 @@ Error HttpClient::SendRequest(const HttpRequest& request,
}
boost::system::error_code ec;
tcp::resolver::results_type endpoints =
resolver.resolve(tcp::v4(), request.host(), port, ec);
// tcp::resolver::results_type
auto endpoints = resolver.resolve(tcp::v4(), request.host(), port, ec);
if (ec) {
LOG_ERRO("cannot resolve host: %s, %s",
request.host().c_str(),
port.c_str());
return kHostResolveError;
}
@ -84,9 +86,7 @@ Error HttpClient::SendRequest(const HttpRequest& request,
// Send HTTP request.
#if WEBCC_DEBUG_OUTPUT
std::cout << "--- REQUEST ---" << std::endl << request << std::endl;
#endif
LOG_VERB("http request:\n{\n%s}", request.Dump().c_str());
try {
boost::asio::write(socket, request.ToBuffers());
@ -94,10 +94,6 @@ Error HttpClient::SendRequest(const HttpRequest& request,
return kSocketWriteError;
}
#if WEBCC_DEBUG_OUTPUT
std::cout << "--- RESPONSE ---" << std::endl;
#endif
// Read and parse HTTP response.
HttpResponseParser parser(response);
@ -119,26 +115,18 @@ Error HttpClient::SendRequest(const HttpRequest& request,
return kSocketReadError;
}
#if WEBCC_DEBUG_OUTPUT
// NOTE: the content XML might not be well formated.
std::cout.write(buffer_.data(), length);
#endif
// Parse the response piece just read.
// If the content has been fully received, next time flag "finished_"
// will be set.
Error error = parser.Parse(buffer_.data(), length);
if (error != kNoError) {
LOG_ERRO("failed to parse http response.");
return error;
}
}
#if WEBCC_DEBUG_OUTPUT
std::cout << std::endl;
std::cout << "--- RESPONSE (PARSED) ---" << std::endl;
std::cout << *response << std::endl;
#endif
LOG_VERB("http response:\n{\n%s}", response->Dump().c_str());
return kNoError;
}

@ -1,5 +1,7 @@
#include "webcc/http_request.h"
#include <sstream>
#include "boost/algorithm/string.hpp"
namespace webcc {
@ -13,7 +15,9 @@ std::ostream& operator<<(std::ostream& os, const HttpRequest& request) {
os << std::endl;
os << request.content() << std::endl;
if (!request.content().empty()) {
os << request.content() << std::endl;
}
return os;
}
@ -69,4 +73,10 @@ std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const {
return buffers;
}
std::string HttpRequest::Dump() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
} // namespace webcc

@ -60,6 +60,9 @@ public:
// and not be changed until the write operation has completed.
std::vector<boost::asio::const_buffer> ToBuffers() const;
// Dump as string, only used by logger.
std::string Dump() const;
private:
// HTTP method.
std::string method_;

@ -2,10 +2,7 @@
#include <sstream>
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#include "webcc/logger.h"
#include "webcc/common.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
@ -20,27 +17,16 @@ void HttpRequestHandler::Start(std::size_t count) {
assert(count > 0 && workers_.size() == 0);
for (std::size_t i = 0; i < count; ++i) {
#if WEBCC_DEBUG_OUTPUT
boost::thread* worker =
#endif
workers_.create_thread(std::bind(&HttpRequestHandler::WorkerRoutine, this));
#if WEBCC_DEBUG_OUTPUT
std::cout << "Worker is running (thread: " << worker->get_id() << ")\n";
#endif
}
}
void HttpRequestHandler::Stop() {
#if WEBCC_DEBUG_OUTPUT
std::cout << "Stopping workers...\n";
#endif
LOG_VERB("Stopping workers...");
// Close pending sessions.
for (HttpSessionPtr conn = queue_.Pop(); conn; conn = queue_.Pop()) {
#if WEBCC_DEBUG_OUTPUT
std::cout << "Closing pending session...\n";
#endif
LOG_VERB("Closing pending session...");
conn->Stop();
}
@ -49,23 +35,18 @@ void HttpRequestHandler::Stop() {
workers_.join_all();
#if WEBCC_DEBUG_OUTPUT
std::cout << "All workers have been stopped.\n";
#endif
LOG_VERB("All workers have been stopped.");
}
void HttpRequestHandler::WorkerRoutine() {
#if WEBCC_DEBUG_OUTPUT
boost::thread::id thread_id = boost::this_thread::get_id();
#endif
LOG_VERB("Worker is running.");
for (;;) {
HttpSessionPtr session = queue_.PopOrWait();
if (!session) {
#if WEBCC_DEBUG_OUTPUT
std::cout << "Worker is going to stop (thread: " << thread_id << ")\n";
#endif
LOG_VERB("Worker is going to stop.");
// For stopping next worker.
queue_.Push(HttpSessionPtr());

@ -1,5 +1,6 @@
#include "webcc/http_response.h"
#include <iostream>
#include <sstream>
namespace webcc {
@ -10,8 +11,11 @@ std::ostream& operator<<(std::ostream& os, const HttpResponse& response) {
os << h.name << ": " << h.value << std::endl;
}
os << std::endl << std::endl;
os << response.content();
os << std::endl;
if (!response.content().empty()) {
os << response.content() << std::endl;
}
return os;
}
@ -112,4 +116,10 @@ HttpResponse HttpResponse::Fault(HttpStatus::Enum status) {
return response;
}
std::string HttpResponse::Dump() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
} // namespace webcc

@ -32,6 +32,9 @@ public:
// and not be changed until the write operation has completed.
std::vector<boost::asio::const_buffer> ToBuffers() const;
// Dump as string, only used by logger.
std::string Dump() const;
// Get a fault response when HTTP status is not OK.
static HttpResponse Fault(HttpStatus::Enum status);

@ -2,10 +2,7 @@
#include <signal.h>
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#include "webcc/logger.h"
#include "webcc/http_request_handler.h"
#include "webcc/soap_service.h"
#include "webcc/utility.h"
@ -49,10 +46,7 @@ HttpServer::~HttpServer() {
void HttpServer::Run() {
assert(GetRequestHandler() != NULL);
#if WEBCC_DEBUG_OUTPUT
boost::thread::id thread_id = boost::this_thread::get_id();
std::cout << "Server main thread: " << thread_id << std::endl;
#endif
LOG_VERB("Server is going to run...");
// Start worker threads.
GetRequestHandler()->Start(workers_);

@ -1,13 +1,11 @@
#include "webcc/http_session.h"
#include <vector>
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#include "boost/asio/write.hpp"
#include "boost/date_time/posix_time/posix_time.hpp"
#include "webcc/logger.h"
#include "webcc/http_request_handler.h"
namespace webcc {
@ -94,25 +92,15 @@ void HttpSession::HandleRead(boost::system::error_code ec,
// ensured by Asio.
void HttpSession::HandleWrite(boost::system::error_code ec,
std::size_t length) {
#if WEBCC_DEBUG_OUTPUT
boost::thread::id thread_id = boost::this_thread::get_id();
#endif
if (!ec) {
#if WEBCC_DEBUG_OUTPUT
std::cout << "Response has been sent back (thread: " << thread_id << ")\n";
#endif
LOG_VERB("Response has been sent back.");
// Initiate graceful connection closure.
boost::system::error_code ec;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
} else {
#if WEBCC_DEBUG_OUTPUT
std::cout << "(thread: " << thread_id << ") Sending response error: "
<< ec.message()
<< std::endl;
#endif
LOG_ERRO("Sending response error: %s", ec.message().c_str());
if (ec != boost::asio::error::operation_aborted) {
Stop();

@ -0,0 +1,74 @@
#include "webcc/logger.h"
#if WEBCC_ENABLE_LOG
#include <cassert>
#include <cstdarg>
#include <mutex>
#include "boost/thread.hpp" // For thread ID.
namespace webcc {
////////////////////////////////////////////////////////////////////////////////
static std::string GetThreadId() {
boost::thread::id thread_id = boost::this_thread::get_id();
std::stringstream ss;
ss << thread_id;
return ss.str();
}
////////////////////////////////////////////////////////////////////////////////
static const char* kLevelNames[] = {
"VERB", "INFO", "WARN", "ERRO", "FATA"
};
struct Logger {
int level;
int modes;
std::mutex mutex;
};
// Global logger.
static Logger g_logger{ VERB };
////////////////////////////////////////////////////////////////////////////////
void LogInit(int level, int modes) {
g_logger.modes = modes;
g_logger.level = level;
}
void LogWrite(int level, const char* file, int line, const char* format, ...) {
assert(format != nullptr);
if (g_logger.level > level) {
return;
}
std::lock_guard<std::mutex> lock(g_logger.mutex);
va_list va_ptr_console;
va_start(va_ptr_console, format);
fprintf(stderr,
"%s, %5s, %24s, %4d, ",
kLevelNames[level],
GetThreadId().c_str(),
file,
line);
vfprintf(stderr, format, va_ptr_console);
fprintf(stderr, "\n");
if ((g_logger.modes & FLUSH) == FLUSH) {
fflush(stderr);
}
va_end(va_ptr_console);
}
} // namespace webcc
#endif // WEBCC_ENABLE_LOG

@ -0,0 +1,94 @@
#ifndef WEBCC_LOGGER_H_
#define WEBCC_LOGGER_H_
// Simple console logger.
namespace webcc {
#if WEBCC_ENABLE_LOG
enum LogLevel {
VERB = 0,
INFO,
WARN,
ERRO,
FATA,
};
enum LogMode {
FLUSH = 1,
};
void LogInit(int level, int modes);
void LogWrite(int level, const char* file, int line, const char* format, ...);
// Initialize the logger with a level.
// E.g., LOG_INIT(ERRO, FLUSH)
#define LOG_INIT(level, modes) LogInit(level, modes);
#if (defined(WIN32) || defined(_WIN64))
// See: https://stackoverflow.com/a/8488201
#define __FILENAME__ strrchr("\\" __FILE__, '\\') + 1
#define LOG_VERB(format, ...) \
LogWrite(VERB, __FILENAME__, __LINE__, format, ##__VA_ARGS__);
#define LOG_INFO(format, ...) \
LogWrite(INFO, __FILENAME__, __LINE__, format, ##__VA_ARGS__);
#define LOG_WARN(format, ...) \
LogWrite(WARN, __FILENAME__, __LINE__, format, ##__VA_ARGS__);
#define LOG_ERRO(format, ...) \
LogWrite(ERRO, __FILENAME__, __LINE__, format, ##__VA_ARGS__);
#define LOG_FATA(format, ...) \
LogWrite(FATA, __FILENAME__, __LINE__, format, ##__VA_ARGS__);
#else
// See: https://stackoverflow.com/a/8488201
#define __FILENAME__ strrchr("/" __FILE__, '/') + 1
#define LOG_VERB(format, args...) \
LogWrite(VERB, __FILENAME__, __LINE__, format, ##args);
#define LOG_INFO(format, args...) \
LogWrite(INFO, __FILENAME__, __LINE__, format, ##args);
#define LOG_WARN(format, args...) \
LogWrite(WARN, __FILENAME__, __LINE__, format, ##args);
#define LOG_ERRO(format, args...) \
LogWrite(ERRO, __FILENAME__, __LINE__, format, ##args);
#define LOG_FATA(format, args...) \
LogWrite(FATA, __FILENAME__, __LINE__, format, ##args);
#endif // defined(WIN32) || defined(_WIN64)
#else // WEBCC_ENABLE_LOG == 0
#define LOG_INIT(level, modes)
#if (defined(WIN32) || defined(_WIN64))
#define LOG_VERB(format, ...)
#define LOG_INFO(format, ...)
#define LOG_WARN(format, ...)
#define LOG_ERRO(format, ...)
#define LOG_FATA(format, ...)
#else
#define LOG_VERB(format, args...)
#define LOG_INFO(format, args...)
#define LOG_WARN(format, args...)
#define LOG_ERRO(format, args...)
#define LOG_FATA(format, args...)
#endif // defined(WIN32) || defined(_WIN64)
#endif // WEBCC_ENABLE_LOG
} // namespace webcc
#endif // WEBCC_LOGGER_H_

@ -1,9 +1,6 @@
#include "webcc/rest_server.h"
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#include "webcc/logger.h"
#include "webcc/url.h"
namespace webcc {
@ -27,9 +24,7 @@ bool RestServiceManager::AddService(RestServicePtr service,
return true;
} catch (std::regex_error& e) {
#if WEBCC_DEBUG_OUTPUT
std::cout << e.what() << std::endl;
#endif
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
}
return false;
@ -76,9 +71,7 @@ HttpStatus::Enum RestRequestHandler::HandleSession(HttpSessionPtr session) {
std::vector<std::string> sub_matches;
RestServicePtr service = service_manager_.GetService(url.path(), &sub_matches);
if (!service) {
#if WEBCC_DEBUG_OUTPUT
std::cout << "No service matches the URL: " << url.path() << std::endl;
#endif
LOG_WARN("No service matches the URL: %s", url.path().c_str());
session->SetResponseStatus(HttpStatus::kBadRequest);
session->SendResponse();
return HttpStatus::kBadRequest;

@ -1,9 +1,6 @@
#include "webcc/soap_server.h"
#if WEBCC_DEBUG_OUTPUT
#include <iostream>
#endif
#include "webcc/logger.h"
#include "webcc/soap_request.h"
#include "webcc/soap_response.h"
@ -55,15 +52,11 @@ SoapServicePtr SoapRequestHandler::GetServiceByUrl(const std::string& url) {
UrlServiceMap::const_iterator it = url_service_map_.find(url);
if (it != url_service_map_.end()) {
#if WEBCC_DEBUG_OUTPUT
std::cout << "Service matches the URL: " << url << std::endl;
#endif
LOG_VERB("Service matches the URL: %s", url.c_str());
return it->second;
}
#if WEBCC_DEBUG_OUTPUT
std::cout << "No service matches the URL: " << url << std::endl;
#endif
LOG_WARN("No service matches the URL: %s", url.c_str());
return SoapServicePtr();
}

Loading…
Cancel
Save