diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5fbfb24 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,85 @@ +name: CI + +on: + push: + branches: [ master, dev ] + pull_request: + branches: [ master, dev ] + +jobs: + build-linux: + runs-on: ubuntu-latest + strategy: + matrix: + fedora: [38, 39, 40] + include: + - fedora: 38 + gcc: 13 + - fedora: 39 + gcc: 13 + - fedora: 40 + gcc: 14 + + container: ghcr.io/fairrootgroup/fairmq-dev/fedora-${{ matrix.fedora }} + + steps: + - uses: actions/checkout@v4 + + - name: Install additional dependencies + run: | + dnf install -y fmt-devel || true + + - name: Configure + run: | + cmake -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DDISABLE_COLOR=ON \ + -DUSE_EXTERNAL_FMT=ON \ + -DUSE_BOOST_PRETTY_FUNCTION=ON + + - name: Build + run: cmake --build build + + - name: Test + run: | + cd build + ctest -V --output-on-failure + + build-macos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-13, macos-14, macos-15] + + steps: + - uses: actions/checkout@v4 + + - name: Cache Homebrew packages + uses: actions/cache@v4 + with: + path: | + ~/Library/Caches/Homebrew + /usr/local/Homebrew/Library/Taps + key: ${{ runner.os }}-${{ matrix.os }}-brew-${{ hashFiles('.github/workflows/ci.yml') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.os }}-brew- + + - name: Install dependencies + run: | + brew install cmake ninja boost fmt + + - name: Configure + run: | + cmake -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DDISABLE_COLOR=ON \ + -DUSE_EXTERNAL_FMT=ON \ + -DUSE_BOOST_PRETTY_FUNCTION=ON + + - name: Build + run: cmake --build build + + - name: Test + run: | + cd build + ctest -V --output-on-failure diff --git a/.gitignore b/.gitignore index f785746..d56d768 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ .vscode +install/ diff --git a/FairLoggerTest.cmake b/FairLoggerTest.cmake index 1267f1a..8bd92a7 100644 --- a/FairLoggerTest.cmake +++ b/FairLoggerTest.cmake @@ -15,14 +15,10 @@ set(CTEST_USE_LAUNCHERS ON) set(CTEST_CONFIGURATION_TYPE "RelWithDebInfo") if(NOT NCPUS) - if(ENV{SLURM_CPUS_PER_TASK}) - set(NCPUS $ENV{SLURM_CPUS_PER_TASK}) - else() - include(ProcessorCount) - ProcessorCount(NCPUS) - if(NCPUS EQUAL 0) - set(NCPUS 1) - endif() + include(ProcessorCount) + ProcessorCount(NCPUS) + if(NCPUS EQUAL 0) + set(NCPUS 1) endif() endif() @@ -32,10 +28,10 @@ else() set(CTEST_SITE $ENV{CTEST_SITE}) endif() -if ("$ENV{LABEL}" STREQUAL "") +if ("$ENV{CTEST_BUILD_NAME}" STREQUAL "") set(CTEST_BUILD_NAME "build") else() - set(CTEST_BUILD_NAME $ENV{LABEL}) + set(CTEST_BUILD_NAME $ENV{CTEST_BUILD_NAME}) endif() ctest_start(Continuous) diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index ad1412f..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,80 +0,0 @@ -#!groovy - -def jobMatrix(String prefix, String type, List specs) { - def nodes = [:] - for (spec in specs) { - job = "${spec.os}-${spec.ver}-${spec.arch}-${spec.compiler}" - def label = "${type}/${job}" - def selector = "${spec.os}-${spec.ver}-${spec.arch}" - def os = spec.os - def ver = spec.ver - def check = spec.check - - nodes[label] = { - node(selector) { - githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING') - try { - deleteDir() - checkout scm - - def jobscript = 'job.sh' - def ctestcmd = "ctest -S FairLoggerTest.cmake -V --output-on-failure" - sh "echo \"set -e\" >> ${jobscript}" - sh "echo \"export LABEL=\\\"\${JOB_BASE_NAME} ${label}\\\"\" >> ${jobscript}" - if (selector =~ /^macos/) { - sh "echo \"${ctestcmd}\" >> ${jobscript}" - sh "cat ${jobscript}" - sh "bash ${jobscript}" - } else { - def containercmd = "singularity exec -B/shared ${env.SINGULARITY_CONTAINER_ROOT}/fairlogger/${os}.${ver}.sif bash -l -c \\\"${ctestcmd}\\\"" - sh """\ - echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript} - echo \"echo \\\"*** Job ID ...............: \\\${SLURM_JOB_ID}\\\"\" >> ${jobscript} - echo \"echo \\\"*** Compute node .........: \\\$(hostname -f)\\\"\" >> ${jobscript} - echo \"unset http_proxy\" >> ${jobscript} - echo \"unset HTTP_PROXY\" >> ${jobscript} - echo \"${containercmd}\" >> ${jobscript} - """ - sh "cat ${jobscript}" - sh "test/ci/slurm-submit.sh \"FairLogger \${JOB_BASE_NAME} ${label}\" ${jobscript}" - } - - deleteDir() - githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS') - } catch (e) { - deleteDir() - githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR') - throw e - } - } - } - } - return nodes -} - -pipeline{ - agent none - stages { - stage("Run CI Matrix") { - steps{ - script { - def builds = jobMatrix('alfa-ci', 'build', [ - [os: 'fedora', ver: '32', arch: 'x86_64', compiler: 'gcc-10'], - [os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'], - [os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11'], - [os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11'], - [os: 'fedora', ver: '36', arch: 'x86_64', compiler: 'gcc-12'], - [os: 'fedora', ver: '37', arch: 'x86_64', compiler: 'gcc-12'], - [os: 'fedora', ver: '38', arch: 'x86_64', compiler: 'gcc-13'], - [os: 'fedora', ver: '39', arch: 'x86_64', compiler: 'gcc-13'], - [os: 'macos', ver: '13', arch: 'x86_64', compiler: 'apple-clang-15'], - [os: 'macos', ver: '14', arch: 'x86_64', compiler: 'apple-clang-15'], - [os: 'macos', ver: '14', arch: 'arm64', compiler: 'apple-clang-15'], - ]) - - parallel(builds) - } - } - } - } -} diff --git a/README.md b/README.md index 1f209bf..e4afef2 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,11 @@ A number of additional logging macros are provided: - `LOGV(severity, verbosity)` Log the line with the provided verbosity, e.g. `LOG(info, veryhigh) << "abcd";` - `LOGF(severity, ...)` The arguments are given to `fmt::printf`, which formats the string using a [printf syntax](https://fmt.dev/dev/api.html#printf-formatting) and the result is logged, e.g. `LOGF(info, "Hello %s!", "world");` - `LOGP(severity, ...)` The arguments are given to `fmt::format`, which formats the string using a [Python-like syntax](https://fmt.dev/dev/syntax.html) and the result is logged, e.g. `LOGP(info, "Hello {}!", "world");` +- `LOGPD(severity, ...)` Same as `LOGP`, but accepts dynamic severity (runtime variable), e.g. `LOGPD(dynamicSeverity, "Hello {}!", "world");` +- `LOGFD(severity, ...)` Same as `LOGF`, but accepts dynamic severity (runtime variable), e.g. `LOGFD(dynamicSeverity, "Hello %s!", "world");` - `LOGN(severity)` Logs an empty line, e.g. `LOGN(info);` - `LOG_IF(severity, condition)` Logs the line if the provided condition if true -- `LOGD(severity, file, line, f)` Logs the line with the provided file, line and function parameters (only if the active verbosity allows it). +- `LOGD(severity, file, line, f)` Logs the line with the provided file, line and function parameters (accepts severity as a variable), e.g. `LOGD(dynamicSeverity, "main.cpp", "42", "main");` ## 3. Severity @@ -224,7 +226,7 @@ If only output from custom sinks is desirable, console/file sinks must be deacti ## Naming conflicts? -By default, `` defines unprefixed macros: `LOG`, `LOGV`, `LOGF`, `LOGP`, `LOGN`, `LOGD`, `LOG_IF`. +By default, `` defines unprefixed macros: `LOG`, `LOGV`, `LOGF`, `LOGP`, `LOGPD`, `LOGFD`, `LOGN`, `LOGD`, `LOG_IF`. Define an option `FAIR_NO_LOG*` to prevent the above unprefixed macros to be defined, e.g. diff --git a/logger/Logger.h b/logger/Logger.h index 42e83d4..faa5682 100644 --- a/logger/Logger.h +++ b/logger/Logger.h @@ -394,16 +394,16 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o #undef LOGV #define LOGV FAIR_LOGV #endif -// allow user of this header file to prevent definition of the LOGF macro, by defining FAIR_NO_LOGF before including this header -#ifndef FAIR_NO_LOGF -#undef LOGF -#define LOGF FAIR_LOGF -#endif // allow user of this header file to prevent definition of the LOGP macro, by defining FAIR_NO_LOGP before including this header #ifndef FAIR_NO_LOGP #undef LOGP #define LOGP FAIR_LOGP #endif +// allow user of this header file to prevent definition of the LOGF macro, by defining FAIR_NO_LOGF before including this header +#ifndef FAIR_NO_LOGF +#undef LOGF +#define LOGF FAIR_LOGF +#endif // allow user of this header file to prevent definition of the LOGN macro, by defining FAIR_NO_LOGN before including this header #ifndef FAIR_NO_LOGN #undef LOGN @@ -419,6 +419,16 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o #undef LOG_IF #define LOG_IF FAIR_LOG_IF #endif +// allow user of this header file to prevent definition of the LOGPD macro, by defining FAIR_NO_LOGPD before including this header +#ifndef FAIR_NO_LOGPD +#undef LOGPD +#define LOGPD FAIR_LOGPD +#endif +// allow user of this header file to prevent definition of the LOGFD macro, by defining FAIR_NO_LOGFD before including this header +#ifndef FAIR_NO_LOGFD +#undef LOGFD +#define LOGFD FAIR_LOGFD +#endif // Log line if the provided severity is below or equals the configured one #define FAIR_LOG(severity) \ @@ -433,8 +443,19 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o fair::Logger(fair::Severity::severity, fair::Verbosity::verbosity, MSG_ORIGIN) // Log with fmt- or printf-like formatting -#define FAIR_LOGP(severity, ...) LOG(severity) << fmt::format(__VA_ARGS__) -#define FAIR_LOGF(severity, ...) LOG(severity) << fmt::sprintf(__VA_ARGS__) +#define FAIR_LOGP(severity, ...) FAIR_LOG(severity) << fmt::format(__VA_ARGS__) +#define FAIR_LOGF(severity, ...) FAIR_LOG(severity) << fmt::sprintf(__VA_ARGS__) + +// Log with fmt- or printf-like formatting (dynamic severity) +#define FAIR_LOGPD(severity, ...) \ + for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \ + for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ + fair::Logger(severity, MSG_ORIGIN) << fmt::format(__VA_ARGS__) + +#define FAIR_LOGFD(severity, ...) \ + for (bool fairLOggerunLikelyvariable3 = false; !fair::Logger::SuppressSeverity(severity) && !fairLOggerunLikelyvariable3; fairLOggerunLikelyvariable3 = true) \ + for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \ + fair::Logger(severity, MSG_ORIGIN) << fmt::sprintf(__VA_ARGS__) // Log an empty line #define FAIR_LOGN(severity) \ @@ -451,6 +472,6 @@ inline std::ostream& operator<<(std::ostream& os, const Verbosity& v) { return o #define FAIR_LOG_IF(severity, condition) \ for (bool fairLOggerunLikelyvariable4 = false; !fair::Logger::SuppressSeverity(fair::Severity::severity) && !fairLOggerunLikelyvariable4; fairLOggerunLikelyvariable4 = true) \ for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \ - LOG(severity) + FAIR_LOG(severity) #endif // FAIR_LOGGER_H diff --git a/test/macros.cxx b/test/macros.cxx index 0947375..05605a8 100644 --- a/test/macros.cxx +++ b/test/macros.cxx @@ -51,6 +51,13 @@ int main() CheckOutput(ToStr(R"(^\[.*\]\[\d{2}:\d{2}:\d{2}\.\d{6}\]\[FATAL\]\[a:4:b\])", " c\n$"), []() { LOGD(Severity::fatal, "a", "4", "b") << "c"; }); + + // Test dynamic severity macros + Logger::SetVerbosity(Verbosity::verylow); + Severity dynamicSeverity = Severity::fatal; + + CheckOutput("^Hello dynamic world :-\\)!\n$", [&]() { LOGPD(dynamicSeverity, "Hello {} {}!", "dynamic world", ":-)"); }); + CheckOutput("^Hello dynamic world :-\\)!\n$", [&]() { LOGFD(dynamicSeverity, "Hello %s %s!", "dynamic world", ":-)"); }); } catch (runtime_error& rte) { cout << rte.what() << endl; return 1;