Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/actions/cmake/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ runs:
# Linux deps
- name: Install/cache clazy, and doctest
if: runner.os != 'Windows'
uses: awalsh128/cache-apt-pkgs-action@v1.3.0
uses: awalsh128/cache-apt-pkgs-action@v1.6.0
with:
packages: doctest-dev clazy
version: 1.0
Expand All @@ -25,10 +25,17 @@ runs:
shell: bash

- name: ccache
uses: hendrikmuhs/[email protected]
uses: hendrikmuhs/[email protected].20
with:
key: ${{ github.job }}

- name: Enable ASAN/UBSAN
if: inputs.asan == 'true'
run: |
echo CFLAGS="-fsanitize=address,undefined ${CFLAGS}" >> "$GITHUB_ENV"
echo CXXFLAGS="-fsanitize=address,undefined ${CXXFLAGS}" >> "$GITHUB_ENV"
shell: bash

- name: Configure CMake
run: |
CFLAGS="-Werror ${CFLAGS}" \
Expand Down
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: github-actions
directories:
- /
- /.github/actions/*
groups:
github-actions-deps:
patterns:
- '*'
schedule:
interval: weekly
25 changes: 25 additions & 0 deletions .github/workflows/auto-add-reviewers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Auto add reviewers

on:
pull_request:
types: [opened, labeled]

jobs:
auto-reviewer:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.labels.*.name, 'dependencies')
permissions:
pull-requests: write

steps:
- name: Add reviewers for dependencies
if: contains(github.event.pull_request.labels.*.name, 'github_actions') || contains(github.event.pull_request.labels.*.name, 'gitsubmodule')
uses: actions/github-script@v8
with:
script: |
await github.rest.pulls.requestReviewers({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
reviewers: ['fvacek', 'syyyr']
});
8 changes: 4 additions & 4 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ on:

jobs:
clang-tidy:
name: clang-tidy / Ubuntu 22.04
name: clang-tidy / Ubuntu
runs-on: ubuntu-22.04
env:
CC: clang-15
CXX: clang++-15
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6

- name: Run clang-tidy
uses: ./.github/actions/run-linter
with:
lint_program_with_args: clang-tidy-15 --quiet --warnings-as-errors=*

clazy:
name: clazy / Ubuntu 22.04
name: clazy / Ubuntu
runs-on: ubuntu-22.04
env:
CC: clang-15
CXX: clang++-15
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6

- name: Run clazy
uses: ./.github/actions/run-linter
Expand Down
60 changes: 22 additions & 38 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,37 @@ concurrency:

on:
push:
branches: [ "master" ]
branches: ["master"]
pull_request:
branches: [ "master" ]
branches: ["master"]

jobs:
ubuntu-qt5:
name: Qt 5.15.2 / Ubuntu 22.04
runs-on: ubuntu-22.04
env:
CFLAGS: -fsanitize=address,undefined
CXXFLAGS: -fsanitize=address,undefined
steps:
- uses: actions/checkout@v3

- name: Setup CMake
uses: ./.github/actions/cmake

- name: Build and test
uses: ./.github/actions/build-and-test

ubuntu-qt6:
name: Qt 6.5.0 / Ubuntu 22.04
runs-on: ubuntu-22.04
env:
CFLAGS: -fsanitize=address,undefined
CXXFLAGS: -fsanitize=address,undefined
steps:
- uses: actions/checkout@v3

- name: Setup CMake
uses: ./.github/actions/cmake

- name: Build and test
uses: ./.github/actions/build-and-test
build-and-test:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: Ubuntu
os: ubuntu-22.04
asan: true
additional_cmake_args: ""

- name: Windows
os: windows-2022
asan: false
additional_cmake_args: >-
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY="${{ github.workspace }}/build/bin"
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY="${{ github.workspace }}/build/bin"

windows:
name: Qt 6.5.0 / Windows
runs-on: windows-2022
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6

- name: Setup CMake
uses: ./.github/actions/cmake
with:
additional_cmake_args: |
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY='${{github.workspace}}/build/bin' \
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY='${{github.workspace}}/build/bin'
additional_cmake_args: ${{ matrix.additional_cmake_args }}

- name: Build and test
uses: ./.github/actions/build-and-test
34 changes: 21 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(CTest)
include(GenerateExportHeader)

set(CMAKE_SHARED_LIBRARY_PREFIX "") # we don't want CMake to prepend "lib" to our libraries, we prefer adding that ourselves

Expand All @@ -22,19 +23,27 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU
set(CMAKE_CXX_FLAGS "${NECROLOG_WARNING_FLAGS} ${CMAKE_CXX_FLAGS}")
endif()

add_library(libnecrolog
libnecrolog/necrolog.cpp
libnecrolog/necrolog.h
libnecrolog/necrologlevel.h
)
add_library(libnecrolog::libnecrolog ALIAS libnecrolog)
add_library(libnecrolog)
generate_export_header(libnecrolog)

target_sources(
libnecrolog
PRIVATE libnecrolog/necrolog.cpp
PUBLIC
FILE_SET HEADERS
BASE_DIRS include
FILES
include/necrolog.h
include/necrologlevel.h
FILE_SET generated_headers
TYPE HEADERS
FILES
BASE_DIRS $<TARGET_PROPERTY:libnecrolog,BINARY_DIR>
FILES "${CMAKE_CURRENT_BINARY_DIR}/libnecrolog_export.h"

target_include_directories(libnecrolog PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/libnecrolog>
$<INSTALL_INTERFACE:include>
)
)

target_compile_definitions(libnecrolog PRIVATE NECROLOG_BUILD_DLL)
add_library(libnecrolog::libnecrolog ALIAS libnecrolog)

if(WITH_EXAMPLES)
add_executable(log_example examples/log_example.cpp)
Expand All @@ -53,15 +62,14 @@ endif()
if(BUILD_TESTING)
add_executable(test_necrolog tests/test_necrolog.cpp)
add_test(NAME test_necrolog COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:test_necrolog>)
target_include_directories(test_necrolog PRIVATE libnecrolog)
target_link_libraries(test_necrolog PRIVATE libnecrolog doctest::doctest)
endif()

include(GNUInstallDirs)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/necrolog.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/necrolog.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/necrolog.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

install(TARGETS libnecrolog EXPORT necrologConfig)
install(TARGETS libnecrolog EXPORT necrologConfig FILE_SET HEADERS FILE_SET generated_headers)
export(TARGETS libnecrolog NAMESPACE libnecrolog:: FILE "${CMAKE_CURRENT_BINARY_DIR}/necrologConfig.cmake")
install(EXPORT necrologConfig DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/necrolog/cmake" NAMESPACE libnecrolog::)

Expand Down
155 changes: 154 additions & 1 deletion include/necrolog.h
Original file line number Diff line number Diff line change
@@ -1 +1,154 @@
#include "../libnecrolog/necrolog.h"
#pragma once

#include "libnecrolog_export.h"
#include "necrologlevel.h"

#include <cstdint>
#include <vector>
#include <string>
#include <map>
#include <memory>
#include <sstream>
#include <functional>

class LIBNECROLOG_EXPORT NecroLog
{
friend class NecroLogSharedData;
public:
using Level = NecroLogLevel;
enum class Color : int8_t {Default = -1, Black, Red, Green, Brown, Blue, Magenta, Cyan, LightGray, Gray, LightRed, LightGreen, Yellow, LightBlue, LightMagenta, LightCyan, White};
class LIBNECROLOG_EXPORT LogContext
{
public:
LogContext() = default;
LogContext(const char *file_name, int line_number, const char *topic)
: m_topic(topic), m_file(file_name), m_line(line_number) {}

const char *topic() const {return m_topic? m_topic: "";}
const char *file() const {return m_file? m_file: "";}
int line() const {return m_line;}

bool isColorSet() const {return m_color != NecroLog::Color::Default;}
NecroLog::Color color() const {return m_color;}
void setColor(NecroLog::Color c) {m_color = c;}

bool isTopicSet() const {return topic()[0];}
//bool isFileSet() const {return file()[0];}
private:
const char *m_topic = nullptr;
const char *m_file = nullptr;
int m_line = 0;
NecroLog::Color m_color = NecroLog::Color::Default;
};

static const char* levelToString(Level level);
static Level stringToLevel(const char *str);

using MessageHandler = std::function<void (Level level, const LogContext &context, const std::string &msg)>;
public:
NecroLog(Level level, const LogContext& log_context)
{
if(level > Level::Invalid)
m_necro = std::make_shared<NecroLogSharedData>(level, log_context);
}

template<typename T>
NecroLog& operator<<(const T &v) {if(m_necro) *m_necro << v; return *this;}
NecroLog& operator<<(bool b) {if(m_necro) *m_necro << (b? "true": "false"); return *this;}
NecroLog& nospace() {if(m_necro) m_necro->setSpace(false); return *this;}
NecroLog& color(NecroLog::Color c) {if(m_necro) m_necro->setColor(c); return *this;}

static NecroLog create(Level level, const LogContext &log_context);
static bool shouldLog(Level level, const LogContext &context);

static MessageHandler setMessageHandler(MessageHandler h);

static void defaultMessageHandler(Level level, const LogContext &context, const std::string &msg);
static void writeWithDefaultFormat(std::ostream &os, bool is_colorized, Level level, const LogContext &context, const std::string &msg);
static std::string moduleFromFileName(const char *file_name);

static std::vector<std::string> setCLIOptions(int argc, char *argv[]);
static std::vector<std::string> setCLIOptions(const std::vector<std::string> &params);
static std::string thresholdsLogInfo();
static std::string topicsLogThresholds();
static void setTopicsLogThresholds(const std::string &thresholds);
static void registerTopic(const std::string &topic, const std::string &info);
static std::string registeredTopicsInfo();
static const char * cliHelp();

enum class ColorizedOutputMode {IfTty, Yes, No };
static ColorizedOutputMode colorizedOutputMode();
static void setColorizedOutputMode(ColorizedOutputMode mode);
private:
struct Options
{
//std::map<std::string, Level> fileTresholds;
std::map<std::string, Level> topicThresholds;
std::map<std::string, std::string> registeredTopics;
bool logLongFileNames = false;
bool caseInsensitiveTopicMatch = false;
ColorizedOutputMode colorizedOutput = ColorizedOutputMode::IfTty;
};

static Options& globalOptions();
static int moduleNameStart(const char *file_name);
private:
class LIBNECROLOG_EXPORT NecroLogSharedData {
friend class NecroLog;
public:
NecroLogSharedData(NecroLog::Level level, const LogContext& log_context);
~NecroLogSharedData();

void setSpace(bool b) {m_isSpace = b;}
void setColor(NecroLog::Color c) {m_logContext.setColor(c);}

template<typename T>
void operator<<(const T &v) {if(m_level != NecroLog::Level::Invalid) {maybeSpace(); m_os << v;}}
private:
void maybeSpace() { if(m_isSpace && m_os.tellp() > 0) m_os << ' '; }
private:
std::ostringstream m_os;
NecroLog::Level m_level;
LogContext m_logContext;
bool m_isSpace = true;
};
private:
std::shared_ptr<NecroLogSharedData> m_necro;
};

//template<> inline NecroLog& NecroLog::operator<<(const bool &b) {if(m_necro) *m_necro << (b? "true": "false"); return *this;}

#ifdef NECROLOG_NO_DEBUG_LOG
#define nCDebug(topic) while(0) NecroLog::create(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, topic))
#else
#define nCDebug(topic) for(bool necrolog__en__ = NecroLog::shouldLog(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, topic)); necrolog__en__; necrolog__en__ = false) NecroLog::create(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, topic))
#endif
#define nCInfo(topic) for(bool necrolog__en__ = NecroLog::shouldLog(NecroLog::Level::Info, NecroLog::LogContext(__FILE__, __LINE__, topic)); necrolog__en__; necrolog__en__ = false) NecroLog::create(NecroLog::Level::Info, NecroLog::LogContext(__FILE__, __LINE__, topic))
#define nCMessage(topic) for(bool necrolog__en__ = NecroLog::shouldLog(NecroLog::Level::Message, NecroLog::LogContext(__FILE__, __LINE__, topic)); necrolog__en__; necrolog__en__ = false) NecroLog::create(NecroLog::Level::Message, NecroLog::LogContext(__FILE__, __LINE__, topic))
#define nCWarning(topic) for(bool necrolog__en__ = NecroLog::shouldLog(NecroLog::Level::Warning, NecroLog::LogContext(__FILE__, __LINE__, topic)); necrolog__en__; necrolog__en__ = false) NecroLog::create(NecroLog::Level::Warning, NecroLog::LogContext(__FILE__, __LINE__, topic))
#define nCError(topic) for(bool necrolog__en__ = NecroLog::shouldLog(NecroLog::Level::Error, NecroLog::LogContext(__FILE__, __LINE__, topic)); necrolog__en__; necrolog__en__ = false) NecroLog::create(NecroLog::Level::Error, NecroLog::LogContext(__FILE__, __LINE__, topic))

#define nDebug() nCDebug("")
#define nMessage() nCMessage("")
#define nInfo() nCInfo("")
#define nWarning() nCWarning("")
#define nError() nCError("")

#ifdef NECROLOG_NO_DEBUG_LOG

#define nLogScope(name) while(0) nDebug()
#define nLogFuncFrame() while(0) nDebug()

#else

#define nLogScope(name) NecroLog __necrolog_func_frame_exit_logger__ = NecroLog::shouldLog(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, ""))? \
NecroLog::create(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, "")) << "<< EXIT scope" << name : \
NecroLog::create(NecroLog::Level::Invalid, NecroLog::LogContext(__FILE__, __LINE__, "")); \
nDebug() << ">> ENTER scope" << name

#define nLogFuncFrame() NecroLog __necrolog_func_frame_exit_logger__ = NecroLog::shouldLog(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, ""))? \
NecroLog::create(NecroLog::Level::Debug, NecroLog::LogContext(__FILE__, __LINE__, "")) << " EXIT FN" << __FUNCTION__ : \
NecroLog::create(NecroLog::Level::Invalid, NecroLog::LogContext(__FILE__, __LINE__, "")); \
nDebug() << ">>>> ENTER FN" << __FUNCTION__

#endif
Loading