Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permit Trace+Debug logging in all non-SGX builds #5375

Merged
merged 25 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3d00c03
Some plumbing for enclave_logging_level option
eddyashton Jun 16, 2023
dd8e1ff
Plumb through end-to-end enclave log-level argument
eddyashton Jun 16, 2023
d614c16
Only need VERBOSE_LOGGING _off_ on SGX
eddyashton Jun 16, 2023
1e18ddf
Set both Python test args via CMake
eddyashton Jun 16, 2023
2a902fc
Hoist logging config object, so we can insert enclave_level
eddyashton Jun 16, 2023
28af455
Merge branch 'main' of github.com:microsoft/CCF into verbose_runtime_…
eddyashton Jun 16, 2023
e4372d0
Format?
eddyashton Jun 16, 2023
1946737
Format for real
eddyashton Jun 19, 2023
25b790a
Merge branch 'main' of github.com:microsoft/CCF into verbose_runtime_…
eddyashton Jun 19, 2023
d5684fd
Merge branch 'main' of github.com:microsoft/CCF into verbose_runtime_…
eddyashton Jul 5, 2023
b89ead1
Reverting enclave log level from JSON config
eddyashton Jul 5, 2023
3ea3073
Add CLI arg to control enclave_log_level
eddyashton Jul 5, 2023
830d042
Pass this arg into enclave, and use it
eddyashton Jul 5, 2023
918f38f
Format?
eddyashton Jul 5, 2023
998af80
Merge branch 'main' of github.com:microsoft/CCF into verbose_runtime_…
eddyashton Jul 6, 2023
ccf080f
EDL doesn't like namespaces. This has knock-on consequences
eddyashton Jul 6, 2023
5255527
And format
eddyashton Jul 6, 2023
183bc9b
Distinguish VERBOSE_LOGGING define from CMake option
eddyashton Jul 6, 2023
7a22c8a
Don't redefine
eddyashton Jul 6, 2023
eae005f
Well sure, yes, ok
eddyashton Jul 6, 2023
4782854
Merge branch 'main' into verbose_runtime_option
achamayou Jul 6, 2023
fa47c37
Small radius lts fix - parse version locally
eddyashton Jul 6, 2023
e65d306
Merge branch 'main' of github.com:microsoft/CCF into verbose_runtime_…
eddyashton Jul 6, 2023
8e2cded
Merge branch 'verbose_runtime_option' of github.com:eddyashton/CCF in…
eddyashton Jul 6, 2023
233465c
CHANGELOG
eddyashton Jul 7, 2023
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [4.0.5]

[4.0.5]: https://github.com/microsoft/CCF/releases/tag/ccf-4.0.5

- Debug logging is now available in non-SGX builds by default, and controlled by a run-time CLI argument (`--enclave-log-level`). On SGX this remains a build-time decision (#5375).

## [4.0.4]

[4.0.4]: https://github.com/microsoft/CCF/releases/tag/ccf-4.0.4
Expand Down
32 changes: 21 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,25 @@ else()
unset(NODES)
endif()

option(VERBOSE_LOGGING "Enable verbose, unsafe logging of enclave code" OFF)
set(TEST_HOST_LOGGING_LEVEL "info")
option(
VERBOSE_LOGGING
"Enable verbose, potentially unsafe logging of enclave code. Affects logging level passed at run-time to end-to-end-tests, and compile-time max verbosity on SGX."
OFF
)
set(TEST_LOGGING_LEVEL "info")
if(VERBOSE_LOGGING)
set(TEST_HOST_LOGGING_LEVEL "trace")
add_compile_definitions(VERBOSE_LOGGING)
set(TEST_LOGGING_LEVEL "trace")
endif()

# NB: Toggling VERBOSE_LOGGING on non-SGX platforms causes no build change, so
# should not cause a rebuild
if(COMPILE_TARGET STREQUAL "sgx" AND NOT VERBOSE_LOGGING)
# Disable verbose, unsafe logging of enclave code. On some platforms it is
# safe to build with this logging enabled, and then it can be disabled at
# run-time. However this run-time control is not possible on SGX, so to ensure
# a given MRENCLAVE cannot leak via debug logging it must be removed at
# build-time, with this option.
add_compile_definitions(CCF_DISABLE_VERBOSE_LOGGING)
endif()

option(USE_NULL_ENCRYPTOR "Turn off encryption of ledger updates - debug only"
Expand Down Expand Up @@ -275,9 +289,6 @@ target_compile_options(
)
target_include_directories(cchost PRIVATE ${CCF_GENERATED_DIR})

# Host is always built with verbose logging enabled, regardless of CMake option
target_compile_definitions(cchost PRIVATE VERBOSE_LOGGING)

if(COMPILE_TARGET STREQUAL "sgx")
target_compile_definitions(cchost PUBLIC PLATFORM_SGX)
elseif(COMPILE_TARGET STREQUAL "snp")
Expand Down Expand Up @@ -434,8 +445,9 @@ set(CCF_NETWORK_TEST_DEFAULT_CONSTITUTION
--constitution
${CCF_DIR}/samples/constitutions/default/apply.js
)
set(CCF_NETWORK_TEST_ARGS --host-log-level ${TEST_HOST_LOGGING_LEVEL}
--worker-threads ${WORKER_THREADS}
set(CCF_NETWORK_TEST_ARGS
--host-log-level ${TEST_LOGGING_LEVEL} --enclave-log-level
${TEST_LOGGING_LEVEL} --worker-threads ${WORKER_THREADS}
)

if(COMPILE_TARGET STREQUAL "sgx")
Expand Down Expand Up @@ -851,7 +863,6 @@ if(BUILD_TESTS)
logger_json_test
${CMAKE_CURRENT_SOURCE_DIR}/src/ds/test/logger_json_test.cpp
)
target_compile_definitions(logger_json_test PUBLIC VERBOSE_LOGGING)

add_unit_test(
kv_test
Expand Down Expand Up @@ -1107,7 +1118,6 @@ if(BUILD_TESTS)
# Picobench benchmarks
add_picobench(map_bench SRCS src/ds/test/map_bench.cpp)
add_picobench(logger_bench SRCS src/ds/test/logger_bench.cpp)
target_compile_definitions(logger_bench PUBLIC VERBOSE_LOGGING)
add_picobench(json_bench SRCS src/ds/test/json_bench.cpp)
add_picobench(ring_buffer_bench SRCS src/ds/test/ring_buffer_bench.cpp)
add_picobench(
Expand Down
6 changes: 5 additions & 1 deletion cmake/version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ unset(CCF_VERSION)
unset(CCF_RELEASE_VERSION)
unset(CCF_VERSION_SUFFIX)

option(UNSAFE_VERSION "Produce build with unsafe logging levels" OFF)
option(
UNSAFE_VERSION
"Append unsafe suffix to project and targets. Should be used on platforms where log level is determined at build-time, to distinguish builds which are unsafely verbose."
OFF
)

set(CCF_PROJECT "ccf_${COMPILE_TARGET}")
if(UNSAFE_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion doc/build_apps/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ These logging functions do several things:
- Prefix formatted metadata. The produced log line will include a timestamp, the name and line number where the line was produced, and an ``[app]`` tag
- Write without an ECALL. The final write must be handled by the host, so writing directly from the enclave would require an expensive ECALL. Instead these macros will queue writes to a ringbuffer for the host to process, so diagnostic logging should not cause significant performance drops

By default, the ``CCF_APP_TRACE`` and ``CCF_APP_DEBUG`` macros are compiled out, to avoid leaking confidential information during execution. To enable these, define ``VERBOSE_LOGGING`` before including ``logger.h`` in your application code. The unsafe build variants of CCF include verbose logging of the framework itself, but this can be used independently of verbose logging in the application code.
The most-verbose lines which are emitted may be restricted at build-time, if required for security on that platform. On SGX, the ``CCF_APP_TRACE`` and ``CCF_APP_DEBUG`` macros are disabled at compile-time, to avoid leaking confidential information during execution. To enable these, define ``VERBOSE_LOGGING`` before including ``logger.h`` in your application code. The unsafe build variants of CCF include verbose logging of the framework itself, but this can be used independently of verbose logging in the application code.

.. note:: The app's logging entries will be interleaved (line-by-line) with the framework's logging messages. Filter for entries containing ``[app]`` to extract only application log lines.

Expand Down
1 change: 0 additions & 1 deletion doc/contribute/build_ccf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ The most common build switches include:
* **BUILD_TESTS**: Boolean. Build all tests for CCF. Default to ON.
* **SAN**: Boolean. Build unit tests with Address and Undefined behaviour sanitizers enabled. Default to OFF.
* **COMPILE_TARGET**: String. Target compilation platform. Defaults to ``sgx``. Supported values are ``sgx``, ``snp``, or ``virtual``.
* **VERBOSE_LOGGING**: Boolean. Enable all logging levels. Default to OFF.

Run Tests
---------
Expand Down
2 changes: 1 addition & 1 deletion doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@
"type": "string",
"enum": ["Trace", "Debug", "Info", "Fail", "Fatal"],
"default": "Info",
"description": "Logging level for the untrusted host. Note: while it is possible to set the host log level at startup, it is deliberately not possible to change the log level of the enclave without rebuilding it and changing its code identity"
"description": "Logging level for the untrusted host."
},
"format": {
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions edl/ccf.edl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enclave {
size_t enclave_version_size,
[out] size_t* enclave_version_len,
StartType start_type,
LoggerLevel enclave_log_level,
size_t num_worker_thread,
[user_check] void* time_location,
);
Expand Down
44 changes: 21 additions & 23 deletions include/ccf/ds/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include "ccf/ds/enum_formatter.h"
#include "ccf/ds/logger_level.h"
#include "ccf/ds/thread_ids.h"

#define FMT_HEADER_ONLY
Expand All @@ -16,22 +17,18 @@

namespace logger
{
enum Level
{
TRACE,
DEBUG, // events useful for debugging
INFO, // important events that should be logged even in release mode
FAIL, // survivable failures that should always be logged
FATAL, // fatal errors that may be non-recoverable
MAX_LOG_LEVEL
};

static constexpr Level MOST_VERBOSE = static_cast<Level>(0);
static constexpr LoggerLevel MOST_VERBOSE =
#ifdef CCF_DISABLE_VERBOSE_LOGGING
LoggerLevel::INFO
#else
LoggerLevel::TRACE
#endif
;

static constexpr const char* LevelNames[] = {
"trace", "debug", "info", "fail", "fatal"};

static constexpr const char* to_string(Level l)
static constexpr const char* to_string(LoggerLevel l)
{
return LevelNames[static_cast<int>(l)];
}
Expand All @@ -48,7 +45,7 @@ namespace logger
{
public:
friend struct Out;
Level log_level;
LoggerLevel log_level;
std::string tag;
std::string file_name;
size_t line_number;
Expand All @@ -58,7 +55,7 @@ namespace logger
std::string msg;

LogLine(
Level level_,
LoggerLevel level_,
std::string_view tag_,
std::string_view file_name_,
size_t line_number_,
Expand Down Expand Up @@ -295,14 +292,14 @@ namespace logger
}
#endif

static inline Level& level()
static inline LoggerLevel& level()
{
static Level the_level = MOST_VERBOSE;
static LoggerLevel the_level = MOST_VERBOSE;

return the_level;
}

static inline bool ok(Level l)
static inline bool ok(LoggerLevel l)
{
return l >= level();
}
Expand All @@ -327,7 +324,7 @@ namespace logger
}

#ifndef INSIDE_ENCLAVE
if (line.log_level == Level::FATAL)
if (line.log_level == LoggerLevel::FATAL)
{
throw std::logic_error("Fatal: " + format_to_text(line));
}
Expand Down Expand Up @@ -358,8 +355,9 @@ namespace logger
// This allows:
// CCF_LOG_OUT(DEBUG, "foo") << "this " << "msg";
#define CCF_LOG_OUT(LVL, TAG) \
logger::config::ok(logger::LVL) && \
logger::Out() == logger::LogLine(logger::LVL, TAG, __FILE__, __LINE__)
logger::config::ok(LoggerLevel::LVL) && \
logger::Out() == \
logger::LogLine(LoggerLevel::LVL, TAG, __FILE__, __LINE__)

// To avoid repeating the (s, ...) args for every macro, we cheat with a curried
// macro here by ending the macro with another macro name, which then accepts
Expand All @@ -382,7 +380,7 @@ namespace logger
# define CCF_LOGGER_DEPRECATE(MACRO)
#endif

#ifdef VERBOSE_LOGGING
#ifndef CCF_DISABLE_VERBOSE_LOGGING
# define LOG_TRACE_FMT \
CCF_LOGGER_DEPRECATE(LOG_TRACE_FMT) CCF_LOG_FMT(TRACE, "")
# define LOG_DEBUG_FMT \
Expand All @@ -391,8 +389,8 @@ namespace logger
# define CCF_APP_TRACE CCF_LOG_FMT(TRACE, "app")
# define CCF_APP_DEBUG CCF_LOG_FMT(DEBUG, "app")
#else
// Without compile-time VERBOSE_LOGGING option, these logging macros are
// compile-time nops (and cannot be enabled by accident or malice)
// With verbose logging disabled by compile-time definition, these logging
// macros are compile-time nops (and cannot be enabled by accident or malice)
# define LOG_TRACE_FMT(...) CCF_LOGGER_DEPRECATE(LOG_TRACE_FMT)((void)0)
# define LOG_DEBUG_FMT(...) CCF_LOGGER_DEPRECATE(LOG_DEBUG_FMT)((void)0)

Expand Down
13 changes: 13 additions & 0 deletions include/ccf/ds/logger_level.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

enum LoggerLevel
{
TRACE,
DEBUG, // events useful for debugging
INFO, // important events that should be logged even in release mode
FAIL, // survivable failures that should always be logged
FATAL, // fatal errors that may be non-recoverable
MAX_LOG_LEVEL
};
3 changes: 0 additions & 3 deletions scripts/scan-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@ export CCC_CXX="clang++-$CLANG_VERSION"

SCAN="scan-build-$CLANG_VERSION --exclude 3rdparty --exclude test"

# VERBOSE_LOGGING=ON is important, without it scan-build will report values as unused
# everywhere we compile out the logging statements that would otherwise read them
$SCAN cmake -GNinja -DCOMPILE_TARGET=virtual -DVERBOSE_LOGGING=ON -DCMAKE_BUILD_TYPE=Debug ..
# Fails on the current build of clang, because of false positives in doctest, WIP
$SCAN ninja || true
17 changes: 7 additions & 10 deletions src/common/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@
#include <string>
#include <vector>

namespace logger
{
DECLARE_JSON_ENUM(
Level,
{{Level::TRACE, "Trace"},
{Level::DEBUG, "Debug"},
{Level::INFO, "Info"},
{Level::FAIL, "Fail"},
{Level::FATAL, "Fatal"}});
}
DECLARE_JSON_ENUM(
LoggerLevel,
{{LoggerLevel::TRACE, "Trace"},
{LoggerLevel::DEBUG, "Debug"},
{LoggerLevel::INFO, "Info"},
{LoggerLevel::FAIL, "Fail"},
{LoggerLevel::FATAL, "Fatal"}});

DECLARE_JSON_ENUM(
StartType,
Expand Down
2 changes: 2 additions & 0 deletions src/common/enclave_interface_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the Apache 2.0 License.
#pragma once

#include "ccf/ds/logger_level.h"

enum CreateNodeStatus
{
/** Call was successful and the node was successfully created */
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/aft/test/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ int main(int argc, char** argv)
#else
logger::config::add_text_console_logger();
#endif
logger::config::level() = logger::DEBUG;
logger::config::level() = LoggerLevel::DEBUG;

threading::ThreadMessaging::init(1);

Expand Down
2 changes: 1 addition & 1 deletion src/consensus/aft/test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ DOCTEST_TEST_CASE("Recv append entries logic" * doctest::test_suite("multiple"))

DOCTEST_TEST_CASE("Exceed append entries limit")
{
logger::config::level() = logger::INFO;
logger::config::level() = LoggerLevel::INFO;

ccf::NodeId node_id0 = kv::test::PrimaryNodeId;
ccf::NodeId node_id1 = kv::test::FirstBackupNodeId;
Expand Down
8 changes: 4 additions & 4 deletions src/ds/test/logger_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static void log_accepted(picobench::state& s)
{
prepare_loggers<LK, Absorb>();

logger::config::level() = logger::DEBUG;
logger::config::level() = LoggerLevel::DEBUG;
{
picobench::scope scope(s);

Expand All @@ -69,7 +69,7 @@ static void log_accepted_fmt(picobench::state& s)
{
prepare_loggers<LK, Absorb>();

logger::config::level() = logger::DEBUG;
logger::config::level() = LoggerLevel::DEBUG;
{
picobench::scope scope(s);

Expand All @@ -87,7 +87,7 @@ static void log_rejected(picobench::state& s)
{
prepare_loggers<LK, Absorb>();

logger::config::level() = logger::FAIL;
logger::config::level() = LoggerLevel::FAIL;
{
picobench::scope scope(s);

Expand All @@ -105,7 +105,7 @@ static void log_rejected_fmt(picobench::state& s)
{
prepare_loggers<LK, Absorb>();

logger::config::level() = logger::FAIL;
logger::config::level() = LoggerLevel::FAIL;
{
picobench::scope scope(s);

Expand Down
2 changes: 1 addition & 1 deletion src/ds/test/logger_json_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ TEST_CASE("Test custom log format")
std::string test_log_file = "./test_json_logger.txt";
remove(test_log_file.c_str());
logger::config::add_json_console_logger();
logger::config::level() = logger::DEBUG;
logger::config::level() = LoggerLevel::DEBUG;
std::string log_msg_dbg = "log_msg_dbg";
std::string log_msg_fail = "log_msg_fail";

Expand Down
2 changes: 1 addition & 1 deletion src/enclave/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ DECLARE_RINGBUFFER_MESSAGE_PAYLOAD(
std::chrono::microseconds::rep,
std::string,
size_t,
logger::Level,
LoggerLevel,
std::string,
uint16_t,
std::string);
Expand Down
Loading