Skip to content

Commit 4aef6cc

Browse files
authored
Add dynamic logging for full_system & thunderscope (UBC-Thunderbots#3539)
1 parent f5926c9 commit 4aef6cc

7 files changed

Lines changed: 91 additions & 12 deletions

File tree

src/.bazelrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ build --per_file_copt=proto/.*,proto/message_translation/.*,proto/primitive/.*,s
7070
# TODO: #3492
7171
# build --per_file_copt=software/.*,shared/.*,-external/.*@-Wconversion
7272

73+
build --cxxopt="-DG3_DYNAMIC_LOGGING"
74+
7375
build --per_file_copt=.*\.pb\.(h|cc|cpp)$@-w
7476
build --per_file_copt=./external/.*,./bazel-out/.*@-w
7577

src/software/logger/logger.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,17 @@ class LoggerSingleton
6363
*/
6464
static void initializeLogger(const std::string& runtime_dir,
6565
const std::shared_ptr<ProtoLogger>& proto_logger,
66-
const bool reduce_repetition = true)
66+
const bool reduce_repetition = true,
67+
const LEVELS minimum_log_level = DEBUG)
6768
{
68-
static std::shared_ptr<LoggerSingleton> s(
69-
new LoggerSingleton(runtime_dir, proto_logger, reduce_repetition));
69+
static LoggerSingleton s(runtime_dir, proto_logger, reduce_repetition,
70+
minimum_log_level);
7071
}
7172

7273
private:
7374
LoggerSingleton(const std::string& runtime_dir,
7475
const std::shared_ptr<ProtoLogger>& proto_logger,
75-
const bool reduce_repetition)
76+
const bool reduce_repetition, const LEVELS minimum_log_level)
7677
{
7778
logWorker = g3::LogWorker::createLogWorker();
7879
// Default locations
@@ -123,6 +124,13 @@ class LoggerSingleton
123124
auto plotjuggler_handle = logWorker->addSink(std::make_unique<PlotJugglerSink>(),
124125
&PlotJugglerSink::sendToPlotJuggler);
125126

127+
g3::log_levels::setHighest(minimum_log_level);
128+
129+
// Add custom logging levels below setHighest to always enable
130+
g3::only_change_at_initialization::addLogLevel(CSV);
131+
g3::only_change_at_initialization::addLogLevel(VISUALIZE);
132+
g3::only_change_at_initialization::addLogLevel(PLOTJUGGLER);
133+
126134
g3::initializeLogging(logWorker.get());
127135
}
128136

src/software/networking/benchmarking_utils/latency_tester_secondary_node_main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
constexpr int SLEEP_DURATION_S = 1;
88

9-
int main(int argc, char **argv)
9+
int main(int argc, char** argv)
1010
{
1111
struct CommandLineArgs
1212
{

src/software/thunderscope/binary_context_managers/full_system.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from software.python_bindings import *
1212
from proto.import_all_protos import *
1313
from software.py_constants import *
14+
from software.thunderscope.constants import LogLevels
1415
from software.thunderscope.binary_context_managers.util import is_cmd_running
1516

1617

@@ -25,6 +26,7 @@ def __init__(
2526
should_restart_on_crash: bool = True,
2627
run_sudo: bool = False,
2728
running_in_realtime: bool = True,
29+
log_level: LogLevels = LogLevels.DEBUG,
2830
) -> None:
2931
"""Run FullSystem
3032
@@ -34,6 +36,7 @@ def __init__(
3436
:param should_restart_on_crash: whether or not to restart the program after it has been crashed
3537
:param run_sudo: true if we should run full system under sudo
3638
:param running_in_realtime: True if we are running fullsystem in realtime, else False
39+
:param log_level: Minimum g3log level that will be printed (DEBUG|INFO|WARNING|FATAL)
3740
"""
3841
self.full_system_runtime_dir = full_system_runtime_dir
3942
self.debug_full_system = debug_full_system
@@ -42,6 +45,7 @@ def __init__(
4245
self.should_restart_on_crash = should_restart_on_crash
4346
self.should_run_under_sudo = run_sudo
4447
self.running_in_realtime = running_in_realtime
48+
self.log_level = log_level
4549

4650
self.thread = threading.Thread(target=self.__restart__, daemon=True)
4751

@@ -61,10 +65,13 @@ def __enter__(self) -> FullSystem:
6165
except:
6266
pass
6367

64-
self.full_system = "software/unix_full_system --runtime_dir={} {} {}".format(
65-
self.full_system_runtime_dir,
66-
"--friendly_colour_yellow" if self.friendly_colour_yellow else "",
67-
"--ci" if not self.running_in_realtime else "",
68+
self.full_system = (
69+
"software/unix_full_system --runtime_dir={} {} {} --log_level={}".format(
70+
self.full_system_runtime_dir,
71+
"--friendly_colour_yellow" if self.friendly_colour_yellow else "",
72+
"--ci" if not self.running_in_realtime else "",
73+
self.log_level.value,
74+
)
6875
)
6976

7077
if self.should_run_under_sudo:

src/software/thunderscope/constants.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pyqtgraph.Qt import QtGui
22
from OpenGL.GL import *
33
from proto.import_all_protos import *
4-
from enum import Enum, IntEnum
4+
from enum import Enum, IntEnum, StrEnum
55
from proto.robot_log_msg_pb2 import LogLevel
66

77
import textwrap
@@ -377,3 +377,12 @@ class ProtoPlayerFlags(Enum):
377377

378378
NO_ERROR_FLAG = 0
379379
UNCAUGHT_EXCEPTION_FLAG = 1 << 0
380+
381+
382+
class LogLevels(StrEnum):
383+
"""Log levels for FullSystem to indicate minimum logged level"""
384+
385+
DEBUG = "DEBUG"
386+
INFO = "INFO"
387+
WARNING = "WARNING"
388+
FATAL = "FATAL"

src/software/thunderscope/thunderscope_main.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from software.thunderscope.estop_helpers import get_estop_config
2626
from software.thunderscope.proto_unix_io import ProtoUnixIO
2727
import software.thunderscope.thunderscope_config as config
28-
from software.thunderscope.constants import CI_DURATION_S
28+
from software.thunderscope.constants import CI_DURATION_S, LogLevels
2929
from software.thunderscope.util import *
3030

3131
from software.thunderscope.binary_context_managers.full_system import FullSystem
@@ -98,6 +98,14 @@
9898
default=False,
9999
help="Visualize C++ Tests",
100100
)
101+
parser.add_argument(
102+
"--log_level",
103+
action="store",
104+
help="Minimum g3log level for full_system logs",
105+
choices=[level for level in LogLevels],
106+
default=LogLevels.DEBUG,
107+
type=LogLevels,
108+
)
101109
parser.add_argument(
102110
"--blue_log",
103111
action="store",
@@ -359,6 +367,7 @@
359367
friendly_colour_yellow=friendly_colour_yellow,
360368
should_restart_on_crash=True,
361369
run_sudo=args.sudo,
370+
log_level=args.log_level,
362371
) as full_system:
363372
full_system.setup_proto_unix_io(current_proto_unix_io)
364373

@@ -432,13 +441,15 @@ def __ticker(tick_rate_ms: int) -> None:
432441
should_restart_on_crash=False,
433442
run_sudo=args.sudo,
434443
running_in_realtime=(not args.ci_mode),
444+
log_level=args.log_level,
435445
) as blue_fs, FullSystem(
436446
full_system_runtime_dir=args.yellow_full_system_runtime_dir,
437447
debug_full_system=args.debug_yellow_full_system,
438448
friendly_colour_yellow=True,
439449
should_restart_on_crash=False,
440450
run_sudo=args.sudo,
441451
running_in_realtime=(not args.ci_mode),
452+
log_level=args.log_level,
442453
) as yellow_fs, Gamecontroller(
443454
suppress_logs=(not args.verbose),
444455
) as gamecontroller, (

src/software/unix_full_system_main.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <filesystem>
55
#include <iostream>
66
#include <numeric>
7+
#include <optional>
78

89
#include "proto/message_translation/ssl_wrapper.h"
910
#include "proto/parameters.pb.h"
@@ -45,6 +46,33 @@ void cleanup(int signal_num)
4546
exit(0);
4647
}
4748

49+
/**
50+
* Parses a string into a LEVELS enum value of DEBUG, INFO, WARNING, or FATAL.
51+
* If the log level is not recognised, returns std::nullopt
52+
*
53+
* @param log_level The log level argument as a string
54+
*/
55+
std::optional<LEVELS> parseLogLevel(const std::string& log_level)
56+
{
57+
if (log_level == "DEBUG")
58+
{
59+
return DEBUG;
60+
}
61+
else if (log_level == "INFO")
62+
{
63+
return INFO;
64+
}
65+
else if (log_level == "WARNING")
66+
{
67+
return WARNING;
68+
}
69+
else if (log_level == "FATAL")
70+
{
71+
return FATAL;
72+
}
73+
return std::nullopt;
74+
}
75+
4876
int main(int argc, char** argv)
4977
{
5078
// Setup dynamic parameters
@@ -54,6 +82,7 @@ int main(int argc, char** argv)
5482
std::string runtime_dir = "/tmp/tbots";
5583
bool friendly_colour_yellow = false;
5684
bool ci = false;
85+
std::string log_level = "DEBUG";
5786
};
5887

5988
CommandLineArgs args;
@@ -70,6 +99,9 @@ int main(int argc, char** argv)
7099
desc.add_options()(
71100
"ci", boost::program_options::bool_switch(&args.ci),
72101
"If true, then the World timestamp will be used to as the time provider for ProtoLogger");
102+
desc.add_options()(
103+
"log_level", boost::program_options::value<std::string>(&args.log_level),
104+
"The minimum g3log level that will be printed (DEBUG|INFO|WARNING|FATAL)");
73105

74106
boost::program_options::variables_map vm;
75107
boost::program_options::store(parse_command_line(argc, argv, desc), vm);
@@ -91,6 +123,15 @@ int main(int argc, char** argv)
91123
TracySetProgramName("Thunderbots: Yellow");
92124
}
93125

126+
std::optional<LEVELS> minimum_log_level = parseLogLevel(args.log_level);
127+
128+
if (!minimum_log_level.has_value())
129+
{
130+
std::cout << "error: --log_level=" << args.log_level
131+
<< " is not a valid option." << std::endl;
132+
return 1;
133+
}
134+
94135
std::function<double()> time_provider;
95136
if (!args.ci)
96137
{
@@ -110,7 +151,8 @@ int main(int argc, char** argv)
110151
}
111152
proto_logger = std::make_shared<ProtoLogger>(args.runtime_dir, time_provider,
112153
args.friendly_colour_yellow);
113-
LoggerSingleton::initializeLogger(args.runtime_dir, proto_logger);
154+
LoggerSingleton::initializeLogger(args.runtime_dir, proto_logger, true,
155+
*minimum_log_level);
114156
TbotsProto::ThunderbotsConfig tbots_proto;
115157

116158
// Override friendly color

0 commit comments

Comments
 (0)