Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas-C committed Jan 15, 2025
1 parent c8cc3ac commit b5cebb0
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 83 deletions.
23 changes: 18 additions & 5 deletions .github/workflows/unix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: Unix Build

on:
push:
branches: [ master ]
branches: [ doc-with-doxygen-and-sphinx ] # Temporary, restore next line before merging MR
# branches: [ master ]
pull_request:
branches: [ master ]

Expand Down Expand Up @@ -82,11 +83,16 @@ jobs:
DEBIAN_FRONTEND: noninteractive
UBSAN_OPTIONS: halt_on_error=1:abort_on_error=1
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- uses: seanmiddleditch/gha-setup-ninja@master
if: matrix.config.os == 'macos-latest'

- name: Install doxygen 🔧
uses: ssciwr/doxygen-install@v1
with:
version: "1.13.2"

# ==== INSTALL ====
- name: Update APT
if: matrix.config.os != 'macos-latest'
Expand Down Expand Up @@ -141,21 +147,28 @@ jobs:
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4

- name: Set up Python 3.13 🔧
uses: actions/setup-python@v5
with:
python-version: 3.13

- name: Install doxygen 🔧
uses: ssciwr/doxygen-install@v1
with:
version: "1.13.2"

- name: Install Python dependencies ⚙️
run: pip install -r docs/requirements.txt

- name: Generate HTML documentation 🏗️
run: |
mkdir -p public/
- name: Deploy documentation 🚀
cd docs
doxygen
sphinx-build -M html . _build
mv _build ../public
- name: Deploy documentation onto GitHub Pages 🚀
if: github.ref == 'refs/heads/master'
uses: peaceiris/actions-gh-pages@v3
with:
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ jobs:
cmake-opt: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- uses: seanmiddleditch/gha-setup-ninja@master

- name: Install doxygen 🔧
uses: ssciwr/doxygen-install@v1
with:
version: "1.13.2"

- uses: ilammy/msvc-dev-cmd@v1

- name: Build
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ endif()
add_executable(utl-test ${utl-test-files})
target_link_libraries(utl-test utl gtest gmock gtest_main)
if (NOT MSVC)
target_compile_options(utl-test PRIVATE -Wall -Wextra -Werror)
target_compile_options(utl-test PRIVATE -Wall -Wextra -Werror -Wno-invalid-token-paste)
endif()

add_subdirectory ("docs")
2 changes: 1 addition & 1 deletion docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ DOXYFILE_ENCODING = UTF-8
# project for which the documentation is generated. This name is used in the
# title of most generated pages and in a few other places.

PROJECT_NAME = "Motis utl module"
PROJECT_NAME = "MOTIS utl module"

# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
Expand Down
7 changes: 6 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Directly with `doxygen`:
doxygen

## Generating Sphinx documentation
From the root directory:
From the root directory, with auto-reload:

sphinx-autobuild docs docs/_build/html --open-browser

Only generating the documentation:

cd docs
sphinx-build -M html . _build
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'Motis utl module'
author = 'The Motis project developers'
copyright = '2025, The Motis project developers'
project = 'MOTIS utl module'
author = 'The MOTIS project developers'
copyright = '2025, The MOTIS project developers'
html_show_copyright = False

# -- General configuration ---------------------------------------------------
Expand Down
41 changes: 32 additions & 9 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Motis utl module documentation
MOTIS utl module documentation
==============================

MOTIS is an open-source software platform for efficient planning and routing in multi-modal transportation systems.
GitHub main repository: https://github.com/motis-project/motis

This is the documentation for the `utl` (utility) module.
This is the documentation for the **utl** (utility) module.

..
Table of contents
Expand All @@ -17,12 +17,35 @@ This is the documentation for the `utl` (utility) module.
Logging
-------

Logs can be produced using the `log()` `struct`::
The simplest way to produce log lines is to use the ``logF()`` macro::

utl::log() << "[" << utl::log::str["info"] << "]" \
<< "[" << utl::time() << "]" \
<< "[" << FILE_NAME << ":" << __LINE__ << "]" \
<< " Some message"
logF(info, "Simple message");

.. doxygenstruct:: utl::log
:members:
The following log levels are supported:

debug
Messages that contain information only useful when debugging MOTIS

info
Important information about a normal behavior of the program

error
Details on an abnormal behavior of the application

Advanced usage
^^^^^^^^^^^^^^

By default, ``logF()`` inserts the current filename & linenumber in the log line.
However, you can use ``log()`` to specify your own **context** ::

log(info, "http.get.resource", "Details");

You can also insert variables in the message by using ``{}`` and passing them as extra arguments::

logF(info, "String={} Int={}", "Hello", 42);

API details
^^^^^^^^^^^
Under the hood, the ``log()`` & ``logF()`` macros use the ``utl::log()`` function:

.. doxygenfunction:: utl::log
115 changes: 62 additions & 53 deletions include/utl/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,84 @@
#else

#include <chrono>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>

#ifdef _MSC_VER
#define gmt(a, b) gmtime_s(b, a)
#else
#define gmt(a, b) gmtime_r(a, b)
#endif
#include "fmt/core.h"
#include "fmt/ostream.h"

#define FILE_NAME \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define STRINGIFY(x) STRINGIFY_(x)
#define STRINGIFY_(x) #x

#define uLOG(lvl) \
utl::log() << "[" << utl::log::str[lvl] << "]" \
<< "[" << utl::time() << "]" \
<< "[" << FILE_NAME << ":" << __LINE__ << "]" \
<< " "
#define FILE_AND_LINE (__FILE__ ":" STRINGIFY(__LINE__))
#if defined(_WIN32)
#define FILE_AND_LINE_SHORT \
(strrchr(FILE_AND_LINE, '\\') ? strrchr(FILE_AND_LINE, '\\') + 1 \
: FILE_AND_LINE)
#else
#define FILE_AND_LINE_SHORT \
(strrchr(FILE_AND_LINE, '/') ? strrchr(FILE_AND_LINE, '/') + 1 \
: FILE_AND_LINE)
#endif

namespace utl {

/**
Entrypoint for all Motis logs
*/
struct log {
log() = default;

log(log const&) = delete;
log& operator=(log const&) = delete;

log(log&&) = default;
log& operator=(log&&) = default;
enum class log_level { debug, info, error };

template <typename T>
friend log&& operator<<(log&& l, T&& t) {
std::clog << std::forward<T&&>(t);
return std::move(l);
constexpr char const* to_str(log_level const level) {
switch (level) {
case log_level::debug: return "debug";
case log_level::info: return "info";
case log_level::error: return "error";
}
return "";
}

~log() { std::clog << std::endl; }

static constexpr const char* const str[]{"emrg", "alrt", "crit", "erro",
"warn", "note", "info", "debg"};
};
static log_level s_verbosity;

enum log_level { emrg, alrt, crit, err, warn, notice, info, debug };
inline std::string now() {
using clock = std::chrono::system_clock;
auto const now = clock::to_time_t(clock::now());
struct tm tmp {};
#if _MSC_VER >= 1400
gmtime_s(&tmp, &now);
#else
gmtime_r(&now, &tmp);
#endif

/**
Format a timestamp as an ISO 8601 string
*/
inline std::string time(time_t const t) {
char buf[sizeof "2011-10-08t07:07:09z-0430"];
struct tm result {};
gmt(&t, &result);
strftime(buf, sizeof buf, "%FT%TZ%z", &result);
return buf;
std::stringstream ss;
ss << std::put_time(&tmp, "%FT%TZ");
return ss.str();
}

/**
Format the current time as an ISO 8601 string
*/
inline std::string time() {
time_t now;
std::time(&now);
return time(now);
/// Produce a new log line at the given `level`, with the given prefix `ctx` and
/// message
template <typename... Args>
void log(log_level const level, char const* ctx,
fmt::format_string<Args...> fmt_str, Args&&... args) {
if (level >= ::utl::s_verbosity) {
fmt::print(std::clog, "{time} [{level}] [{ctx}] {msg}\n",
fmt::arg("time", now()), fmt::arg("level", to_str(level)),
fmt::arg("ctx", ctx),
fmt::arg("msg", fmt::format(fmt::runtime(fmt_str),
std::forward<Args>(args)...)));
}
}

} // namespace utl

#endif
/**
* Shorthand to invoke utl::log without specifying the namespace
*/
#define log(level, ctx, fmt_str, ...) \
utl::log(utl::log_level::##level, ctx, fmt_str, __VA_ARGS__)

/**
* Invoke utl::log using the current C++ filename & line number as ctx
*/
#define logF(level, fmt_str, ...) \
log(level, FILE_AND_LINE_SHORT, fmt_str, __VA_ARGS__)

#endif // LOGGING_HEADER
2 changes: 1 addition & 1 deletion include/utl/parallel_for.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ inline errors_t parallel_for(
jobs.size(),
[&](auto const idx) {
if (idx % mod == 0) {
uLOG(info) << desc << " " << idx << "/" << jobs.size();
logF(info, "{} {}/{}", desc, idx, jobs.size());
}
func(jobs[idx]);
},
Expand Down
14 changes: 6 additions & 8 deletions src/timer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace utl {

scoped_timer::scoped_timer(std::string name)
: name_{std::move(name)}, start_{std::chrono::steady_clock::now()} {
uLOG(info) << "[" << name_ << "] starting";
logF(info, "[{}] starting", name);
}

scoped_timer::~scoped_timer() {
Expand All @@ -15,8 +15,7 @@ scoped_timer::~scoped_timer() {
double t =
static_cast<double>(duration_cast<microseconds>(stop - start_).count()) /
1000.0;
uLOG(info) << "[" << name_ << "] finished"
<< " (" << t << "ms)";
logF(info, "[{}] finished ({}ms)", name_, t);
}

void scoped_timer::print(std::string_view const message) const {
Expand All @@ -25,12 +24,12 @@ void scoped_timer::print(std::string_view const message) const {
double const t =
static_cast<double>(duration_cast<microseconds>(stop - start_).count()) /
1000.0;
uLOG(info) << "[" << name_ << "] " << message << " (" << t << "ms)";
logF(info, "[{}] {} ({}ms)", name_, message, t);
}

manual_timer::manual_timer(std::string name)
: name_{std::move(name)}, start_{std::chrono::steady_clock::now()} {
uLOG(info) << "[" << name_ << "] starting";
logF(info, "[{}] starting", name_);
}

void manual_timer::stop_and_print() const {
Expand All @@ -39,8 +38,7 @@ void manual_timer::stop_and_print() const {
double t =
static_cast<double>(duration_cast<microseconds>(stop - start_).count()) /
1000.0;
uLOG(info) << "[" << name_ << "] finished"
<< " (" << t << "ms)";
logF(info, "[{}] finished ({}ms)", name_, t);
}

void manual_timer::print(std::string_view const message) const {
Expand All @@ -49,7 +47,7 @@ void manual_timer::print(std::string_view const message) const {
double const t =
static_cast<double>(duration_cast<microseconds>(stop - start_).count()) /
1000.0;
uLOG(info) << "[" << name_ << "] " << message << " (" << t << "ms)";
logF(info, "[{}] {} ({}ms)", name_, message, t);
}

} // namespace utl
Loading

0 comments on commit b5cebb0

Please sign in to comment.