Skip to content

Commit 7c70372

Browse files
committed
feat(logging)_: enable runtime logs configuration
Add endpoints for log level and namespaces configuration to `status.go` and deprecate equivalents from service. Endpoints are defined in `status.go`, as it has access to `statusBackend`, the only entity capable of manipulating node configuration without requiring a restart.
1 parent 74db631 commit 7c70372

File tree

6 files changed

+99
-27
lines changed

6 files changed

+99
-27
lines changed

api/geth_backend.go

+26-6
Original file line numberDiff line numberDiff line change
@@ -2079,12 +2079,6 @@ func (b *GethStatusBackend) loadNodeConfig(inputNodeCfg *params.NodeConfig) erro
20792079
}
20802080
}
20812081

2082-
if len(conf.LogDir) == 0 {
2083-
conf.LogFile = filepath.Join(b.rootDataDir, conf.LogFile)
2084-
} else {
2085-
conf.LogFile = filepath.Join(conf.LogDir, conf.LogFile)
2086-
}
2087-
20882082
b.config = conf
20892083

20902084
if inputNodeCfg != nil && inputNodeCfg.RuntimeLogLevel != "" {
@@ -2859,3 +2853,29 @@ func (b *GethStatusBackend) TogglePanicReporting(enabled bool) error {
28592853
}
28602854
return b.DisablePanicReporting()
28612855
}
2856+
2857+
func (b *GethStatusBackend) SetLogLevel(level string) error {
2858+
b.mu.Lock()
2859+
defer b.mu.Unlock()
2860+
2861+
err := nodecfg.SetLogLevel(b.appDB, level)
2862+
if err != nil {
2863+
return err
2864+
}
2865+
b.config.LogLevel = level
2866+
2867+
return logutils.OverrideRootLoggerWithConfig(b.config.LogSettings())
2868+
}
2869+
2870+
func (b *GethStatusBackend) SetLogNamespaces(namespaces string) error {
2871+
b.mu.Lock()
2872+
defer b.mu.Unlock()
2873+
2874+
err := nodecfg.SetLogNamespaces(b.appDB, namespaces)
2875+
if err != nil {
2876+
return err
2877+
}
2878+
b.config.LogNamespaces = namespaces
2879+
2880+
return logutils.OverrideRootLoggerWithConfig(b.config.LogSettings())
2881+
}

logutils/core.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ func (core *Core) Sync() error {
107107
}
108108

109109
func (core *Core) UpdateSyncer(newSyncer zapcore.WriteSyncer) {
110-
core.syncer.Store(writeSyncerWrapper{WriteSyncer: newSyncer})
110+
oldSyncer := core.syncer.Swap(writeSyncerWrapper{WriteSyncer: newSyncer})
111+
_ = oldSyncer.(zapcore.WriteSyncer).Sync() // may fail but doesn't impact syncer update
111112
}
112113

113114
func (core *Core) UpdateEncoder(newEncoder zapcore.Encoder) {

mobile/status.go

+39-1
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,7 @@ func exportNodeLogs() string {
12251225
if config == nil {
12261226
return makeJSONResponse(errors.New("config and log file are not available"))
12271227
}
1228-
data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFile))
1228+
data, err := json.Marshal(exportlogs.ExportFromBaseFile(config.LogFilePath()))
12291229
if err != nil {
12301230
return makeJSONResponse(fmt.Errorf("error marshalling to json: %v", err))
12311231
}
@@ -2297,6 +2297,44 @@ func addCentralizedMetric(requestJSON string) string {
22972297
return metric.ID
22982298
}
22992299

2300+
func SetLogLevel(requestJSON string) string {
2301+
return callWithResponse(setLogLevel, requestJSON)
2302+
}
2303+
2304+
func setLogLevel(requestJSON string) string {
2305+
var request requests.SetLogLevel
2306+
err := json.Unmarshal([]byte(requestJSON), &request)
2307+
if err != nil {
2308+
return makeJSONResponse(err)
2309+
}
2310+
2311+
err = request.Validate()
2312+
if err != nil {
2313+
return makeJSONResponse(err)
2314+
}
2315+
2316+
return makeJSONResponse(statusBackend.SetLogLevel(request.LogLevel))
2317+
}
2318+
2319+
func SetLogNamespaces(requestJSON string) string {
2320+
return callWithResponse(setLogNamespaces, requestJSON)
2321+
}
2322+
2323+
func setLogNamespaces(requestJSON string) string {
2324+
var request requests.SetLogNamespaces
2325+
err := json.Unmarshal([]byte(requestJSON), &request)
2326+
if err != nil {
2327+
return makeJSONResponse(err)
2328+
}
2329+
2330+
err = request.Validate()
2331+
if err != nil {
2332+
return makeJSONResponse(err)
2333+
}
2334+
2335+
return makeJSONResponse(statusBackend.SetLogNamespaces(request.LogNamespaces))
2336+
}
2337+
23002338
func IntendedPanic(message string) string {
23012339
type intendedPanic struct {
23022340
error

params/config.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -1196,12 +1196,19 @@ func LesTopic(netid int) string {
11961196
}
11971197
}
11981198

1199+
func (c *NodeConfig) LogFilePath() string {
1200+
if len(c.LogDir) == 0 {
1201+
return filepath.Join(c.RootDataDir, c.LogFile)
1202+
}
1203+
return filepath.Join(c.LogDir, c.LogFile)
1204+
}
1205+
11991206
func (c *NodeConfig) LogSettings() logutils.LogSettings {
12001207
return logutils.LogSettings{
12011208
Enabled: c.LogEnabled,
12021209
Level: c.LogLevel,
12031210
Namespaces: c.LogNamespaces,
1204-
File: c.LogFile,
1211+
File: c.LogFilePath(),
12051212
MaxSize: c.LogMaxSize,
12061213
MaxBackups: c.LogMaxBackups,
12071214
CompressRotated: c.LogCompressRotated,

protocol/messenger_settings.go

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func (m *Messenger) SetSyncingOnMobileNetwork(request *requests.SetSyncingOnMobi
3030
return nil
3131
}
3232

33+
// Deprecated: Use SetLogLevel from status.go instead.
3334
func (m *Messenger) SetLogLevel(request *requests.SetLogLevel) error {
3435
if err := request.Validate(); err != nil {
3536
return err
@@ -38,6 +39,7 @@ func (m *Messenger) SetLogLevel(request *requests.SetLogLevel) error {
3839
return nodecfg.SetLogLevel(m.database, request.LogLevel)
3940
}
4041

42+
// Deprecated: Use SetLogNamespaces from status.go instead.
4143
func (m *Messenger) SetLogNamespaces(request *requests.SetLogNamespaces) error {
4244
if err := request.Validate(); err != nil {
4345
return err

tests-functional/tests/test_logging.py

+22-18
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,38 @@ def test_logging(self, tmp_path):
2626
key_uid = self.ensure_logged_in(backend_client)
2727

2828
# Configure logging
29-
backend_client.rpc_valid_request("wakuext_setLogLevel", [{"logLevel": "ERROR"}])
30-
backend_client.rpc_valid_request("wakuext_setLogNamespaces", [{"logNamespaces": "test1.test2:debug,test1.test2.test3:info"}])
29+
backend_client.api_valid_request("SetLogLevel", {"logLevel": "ERROR"})
30+
backend_client.api_valid_request("SetLogNamespaces", {"logNamespaces": "test1.test2:debug,test1.test2.test3:info"})
3131

32-
# Re-login (logging settings take effect after re-login)
32+
log_pattern = [
33+
r"DEBUG\s+test1\.test2\s+",
34+
r"INFO\s+test1\.test2\s+",
35+
r"INFO\s+test1\.test2\.test3\s+",
36+
r"WARN\s+test1\.test2\s+",
37+
r"WARN\s+test1\.test2\.test3\s+",
38+
r"ERROR\s+test1\s+",
39+
r"ERROR\s+test1\.test2\s+",
40+
r"ERROR\s+test1\.test2\.test3\s+",
41+
]
42+
43+
# Ensure changes take effect at runtime
44+
backend_client.rpc_valid_request("wakuext_logTest")
45+
self.expect_logs(tmp_path / "geth.log", "test message", log_pattern, count=1)
46+
47+
# Ensure changes are persisted after re-login
3348
backend_client.logout()
3449
backend_client.login(str(key_uid))
3550
self.ensure_logged_in(backend_client)
36-
37-
# Test logging
3851
backend_client.rpc_valid_request("wakuext_logTest")
39-
self.expect_logs(tmp_path / "geth.log", "test message", [
40-
r"DEBUG\s+test1\.test2",
41-
r"INFO\s+test1\.test2",
42-
r"INFO\s+test1\.test2\.test3",
43-
r"WARN\s+test1\.test2",
44-
r"WARN\s+test1\.test2\.test3",
45-
r"ERROR\s+test1",
46-
r"ERROR\s+test1\.test2",
47-
r"ERROR\s+test1\.test2\.test3",
48-
])
49-
50-
def expect_logs(self, log_file, filter_keyword, expected_logs):
52+
self.expect_logs(tmp_path / "geth.log", "test message", log_pattern, count=2)
53+
54+
def expect_logs(self, log_file, filter_keyword, expected_logs, count):
5155
with open(log_file, 'r') as f:
5256
log_content = f.read()
5357

5458
filtered_logs = [line for line in log_content.splitlines() if filter_keyword in line]
5559
for expected_log in expected_logs:
56-
assert any(re.search(expected_log, log) for log in filtered_logs), f"Log entry not found: {expected_log}"
60+
assert sum(1 for log in filtered_logs if re.search(expected_log, log)) == count, f"Log entry not found or count mismatch: {expected_log}"
5761

5862
def ensure_logged_in(self, backend_client):
5963
login_response = backend_client.wait_for_signal("node.login")

0 commit comments

Comments
 (0)