Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/firecracker
Path: blob/main/tests/integration_tests/functional/test_logging.py
1958 views
1
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
# SPDX-License-Identifier: Apache-2.0
3
"""Tests the format of human readable logs.
4
5
It checks the response of the API configuration calls and the logs that show
6
up in the configured logging FIFO.
7
"""
8
import os
9
import re
10
11
from time import strptime
12
13
import host_tools.logging as log_tools
14
15
16
# Array of supported log levels of the current logging system.
17
# Do not change order of values inside this array as logic depends on this.
18
LOG_LEVELS = ["ERROR", "WARN", "INFO", "DEBUG"]
19
20
21
def to_formal_log_level(log_level):
22
"""Convert a pretty-print log level into the related log level code.
23
24
Turns a pretty formatted log level (i.e Warning) into the one actually
25
being logged (i.e WARN).
26
:param log_level: pretty formatted log level
27
:return: actual level being logged
28
"""
29
if log_level == "Error":
30
return LOG_LEVELS[0]
31
if log_level == "Warning":
32
return LOG_LEVELS[1]
33
if log_level == "Info":
34
return LOG_LEVELS[2]
35
if log_level == "Debug":
36
return LOG_LEVELS[3]
37
return ""
38
39
40
def check_log_message_format(log_str, instance_id, level, show_level,
41
show_origin):
42
"""Ensure correctness of the logged message.
43
44
Parse the string representing the logs and look for the parts
45
that should be there.
46
The log line should look lie this:
47
YYYY-MM-DDTHH:MM:SS.NNNNNNNNN [ID:THREAD:LEVEL:FILE:LINE] MESSAGE
48
where LEVEL and FILE:LINE are both optional.
49
e.g. with THREAD NAME as TN
50
`2018-09-09T12:52:00.123456789 [MYID:TN:WARN:/path/to/file.rs:52] warning`
51
"""
52
(timestamp, tag, _) = log_str.split(' ')[:3]
53
timestamp = timestamp[:-10]
54
strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
55
56
pattern = "\\[(" + instance_id + ")"
57
pattern += ":(.*)"
58
if show_level:
59
pattern += ":(" + "|".join(LOG_LEVELS) + ")"
60
if show_origin:
61
pattern += ":([^:]+/[^:]+):([0-9]+)"
62
pattern += "\\]"
63
64
mo = re.match(pattern, tag)
65
assert mo is not None
66
67
if show_level:
68
tag_level = mo.group(3)
69
tag_level_no = LOG_LEVELS.index(tag_level)
70
configured_level_no = LOG_LEVELS.index(to_formal_log_level(level))
71
assert tag_level_no <= configured_level_no
72
73
74
def test_no_origin_logs(test_microvm_with_ssh):
75
"""Check that logs do not contain the origin (i.e file and line number)."""
76
_test_log_config(
77
microvm=test_microvm_with_ssh,
78
show_level=True,
79
show_origin=False
80
)
81
82
83
def test_no_level_logs(test_microvm_with_ssh):
84
"""Check that logs do not contain the level."""
85
_test_log_config(
86
microvm=test_microvm_with_ssh,
87
show_level=False,
88
show_origin=True
89
)
90
91
92
def test_no_nada_logs(test_microvm_with_ssh):
93
"""Check that logs do not contain either level or origin."""
94
_test_log_config(
95
microvm=test_microvm_with_ssh,
96
show_level=False,
97
show_origin=False
98
)
99
100
101
def test_info_logs(test_microvm_with_ssh):
102
"""Check output of logs when minimum level to be displayed is info."""
103
_test_log_config(microvm=test_microvm_with_ssh)
104
105
106
def test_warn_logs(test_microvm_with_ssh):
107
"""Check output of logs when minimum level to be displayed is warning."""
108
_test_log_config(
109
microvm=test_microvm_with_ssh,
110
log_level='Warning'
111
)
112
113
114
def test_error_logs(test_microvm_with_ssh):
115
"""Check output of logs when minimum level of logs displayed is error."""
116
_test_log_config(
117
microvm=test_microvm_with_ssh,
118
log_level='Error'
119
)
120
121
122
def test_log_config_failure(test_microvm_with_api):
123
"""Check passing invalid FIFOs is detected and reported as an error."""
124
microvm = test_microvm_with_api
125
microvm.spawn(create_logger=False)
126
microvm.basic_config()
127
128
response = microvm.logger.put(
129
log_path='invalid log fifo',
130
level='Info',
131
show_level=True,
132
show_log_origin=True,
133
)
134
assert microvm.api_session.is_status_bad_request(response.status_code)
135
assert response.json()['fault_message']
136
137
138
def test_api_requests_logs(test_microvm_with_api):
139
"""Test that API requests are logged."""
140
microvm = test_microvm_with_api
141
microvm.spawn(create_logger=False)
142
microvm.basic_config()
143
144
# Configure logging.
145
log_fifo_path = os.path.join(microvm.path, 'log_fifo')
146
log_fifo = log_tools.Fifo(log_fifo_path)
147
148
response = microvm.logger.put(
149
log_path=microvm.create_jailed_resource(log_fifo.path),
150
level='Info',
151
show_level=True,
152
show_log_origin=True,
153
)
154
assert microvm.api_session.is_status_no_content(response.status_code)
155
microvm.start_console_logger(log_fifo)
156
157
# Check that a Patch request on /machine-config is logged.
158
response = microvm.machine_cfg.patch(vcpu_count=4)
159
assert microvm.api_session.is_status_no_content(response.status_code)
160
# We are not interested in the actual body. Just check that the log
161
# message also has the string "body" in it.
162
microvm.check_log_message(
163
"The API server received a Patch request "
164
"on \"/machine-config\" with body"
165
)
166
167
# Check that a Put request on /machine-config is logged.
168
response = microvm.machine_cfg.put(
169
vcpu_count=4,
170
ht_enabled=False,
171
mem_size_mib=128
172
)
173
assert microvm.api_session.is_status_no_content(response.status_code)
174
microvm.check_log_message(
175
"The API server received a Put request "
176
"on \"/machine-config\" with body"
177
)
178
179
# Check that a Get request on /machine-config is logged without the
180
# body.
181
response = microvm.machine_cfg.get()
182
assert microvm.api_session.is_status_ok(response.status_code)
183
microvm.check_log_message(
184
"The API server received a Get request "
185
"on \"/machine-config\"."
186
)
187
188
# Check that all requests on /mmds are logged without the body.
189
dummy_json = {
190
'latest': {
191
'meta-data': {
192
'ami-id': 'dummy'
193
}
194
}
195
}
196
response = microvm.mmds.put(json=dummy_json)
197
assert microvm.api_session.is_status_no_content(response.status_code)
198
microvm.check_log_message(
199
"The API server received a Put request on \"/mmds\"."
200
)
201
202
response = microvm.mmds.patch(json=dummy_json)
203
assert microvm.api_session.is_status_no_content(response.status_code)
204
microvm.check_log_message(
205
"The API server received a Patch request on \"/mmds\"."
206
)
207
208
response = microvm.mmds.get()
209
assert microvm.api_session.is_status_ok(response.status_code)
210
microvm.check_log_message(
211
"The API server received a Get request on \"/mmds\"."
212
)
213
214
# Check that the fault message return by the client is also logged in the
215
# FIFO.
216
response = microvm.boot.put(
217
kernel_image_path="inexistent_path"
218
)
219
assert microvm.api_session.is_status_bad_request(response.status_code)
220
fault_message = "The kernel file cannot be opened: No such file or " \
221
"directory (os error 2)"
222
assert fault_message in response.text
223
microvm.check_log_message("Received Error. "
224
"Status code: 400 Bad Request. "
225
"Message: {}".format(fault_message))
226
227
228
# pylint: disable=W0102
229
def _test_log_config(
230
microvm,
231
log_level='Info',
232
show_level=True,
233
show_origin=True
234
):
235
"""Exercises different scenarios for testing the logging config."""
236
microvm.spawn(create_logger=False)
237
238
# Configure logging.
239
log_fifo_path = os.path.join(microvm.path, 'log_fifo')
240
log_fifo = log_tools.Fifo(log_fifo_path)
241
response = microvm.logger.put(
242
log_path=microvm.create_jailed_resource(log_fifo.path),
243
level=log_level,
244
show_level=show_level,
245
show_log_origin=show_origin
246
)
247
assert microvm.api_session.is_status_no_content(response.status_code)
248
249
microvm.start_console_logger(log_fifo)
250
251
microvm.basic_config()
252
microvm.start()
253
254
lines = microvm.log_data.splitlines()
255
for idx, line in enumerate(lines):
256
if idx == 0:
257
assert line.startswith("Running Firecracker")
258
continue
259
check_log_message_format(
260
line,
261
microvm.id,
262
log_level,
263
show_level,
264
show_origin
265
)
266
267