Path: blob/main/tests/integration_tests/functional/test_logging.py
1958 views
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.1# SPDX-License-Identifier: Apache-2.02"""Tests the format of human readable logs.34It checks the response of the API configuration calls and the logs that show5up in the configured logging FIFO.6"""7import os8import re910from time import strptime1112import host_tools.logging as log_tools131415# Array of supported log levels of the current logging system.16# Do not change order of values inside this array as logic depends on this.17LOG_LEVELS = ["ERROR", "WARN", "INFO", "DEBUG"]181920def to_formal_log_level(log_level):21"""Convert a pretty-print log level into the related log level code.2223Turns a pretty formatted log level (i.e Warning) into the one actually24being logged (i.e WARN).25:param log_level: pretty formatted log level26:return: actual level being logged27"""28if log_level == "Error":29return LOG_LEVELS[0]30if log_level == "Warning":31return LOG_LEVELS[1]32if log_level == "Info":33return LOG_LEVELS[2]34if log_level == "Debug":35return LOG_LEVELS[3]36return ""373839def check_log_message_format(log_str, instance_id, level, show_level,40show_origin):41"""Ensure correctness of the logged message.4243Parse the string representing the logs and look for the parts44that should be there.45The log line should look lie this:46YYYY-MM-DDTHH:MM:SS.NNNNNNNNN [ID:THREAD:LEVEL:FILE:LINE] MESSAGE47where LEVEL and FILE:LINE are both optional.48e.g. with THREAD NAME as TN49`2018-09-09T12:52:00.123456789 [MYID:TN:WARN:/path/to/file.rs:52] warning`50"""51(timestamp, tag, _) = log_str.split(' ')[:3]52timestamp = timestamp[:-10]53strptime(timestamp, "%Y-%m-%dT%H:%M:%S")5455pattern = "\\[(" + instance_id + ")"56pattern += ":(.*)"57if show_level:58pattern += ":(" + "|".join(LOG_LEVELS) + ")"59if show_origin:60pattern += ":([^:]+/[^:]+):([0-9]+)"61pattern += "\\]"6263mo = re.match(pattern, tag)64assert mo is not None6566if show_level:67tag_level = mo.group(3)68tag_level_no = LOG_LEVELS.index(tag_level)69configured_level_no = LOG_LEVELS.index(to_formal_log_level(level))70assert tag_level_no <= configured_level_no717273def test_no_origin_logs(test_microvm_with_ssh):74"""Check that logs do not contain the origin (i.e file and line number)."""75_test_log_config(76microvm=test_microvm_with_ssh,77show_level=True,78show_origin=False79)808182def test_no_level_logs(test_microvm_with_ssh):83"""Check that logs do not contain the level."""84_test_log_config(85microvm=test_microvm_with_ssh,86show_level=False,87show_origin=True88)899091def test_no_nada_logs(test_microvm_with_ssh):92"""Check that logs do not contain either level or origin."""93_test_log_config(94microvm=test_microvm_with_ssh,95show_level=False,96show_origin=False97)9899100def test_info_logs(test_microvm_with_ssh):101"""Check output of logs when minimum level to be displayed is info."""102_test_log_config(microvm=test_microvm_with_ssh)103104105def test_warn_logs(test_microvm_with_ssh):106"""Check output of logs when minimum level to be displayed is warning."""107_test_log_config(108microvm=test_microvm_with_ssh,109log_level='Warning'110)111112113def test_error_logs(test_microvm_with_ssh):114"""Check output of logs when minimum level of logs displayed is error."""115_test_log_config(116microvm=test_microvm_with_ssh,117log_level='Error'118)119120121def test_log_config_failure(test_microvm_with_api):122"""Check passing invalid FIFOs is detected and reported as an error."""123microvm = test_microvm_with_api124microvm.spawn(create_logger=False)125microvm.basic_config()126127response = microvm.logger.put(128log_path='invalid log fifo',129level='Info',130show_level=True,131show_log_origin=True,132)133assert microvm.api_session.is_status_bad_request(response.status_code)134assert response.json()['fault_message']135136137def test_api_requests_logs(test_microvm_with_api):138"""Test that API requests are logged."""139microvm = test_microvm_with_api140microvm.spawn(create_logger=False)141microvm.basic_config()142143# Configure logging.144log_fifo_path = os.path.join(microvm.path, 'log_fifo')145log_fifo = log_tools.Fifo(log_fifo_path)146147response = microvm.logger.put(148log_path=microvm.create_jailed_resource(log_fifo.path),149level='Info',150show_level=True,151show_log_origin=True,152)153assert microvm.api_session.is_status_no_content(response.status_code)154microvm.start_console_logger(log_fifo)155156# Check that a Patch request on /machine-config is logged.157response = microvm.machine_cfg.patch(vcpu_count=4)158assert microvm.api_session.is_status_no_content(response.status_code)159# We are not interested in the actual body. Just check that the log160# message also has the string "body" in it.161microvm.check_log_message(162"The API server received a Patch request "163"on \"/machine-config\" with body"164)165166# Check that a Put request on /machine-config is logged.167response = microvm.machine_cfg.put(168vcpu_count=4,169ht_enabled=False,170mem_size_mib=128171)172assert microvm.api_session.is_status_no_content(response.status_code)173microvm.check_log_message(174"The API server received a Put request "175"on \"/machine-config\" with body"176)177178# Check that a Get request on /machine-config is logged without the179# body.180response = microvm.machine_cfg.get()181assert microvm.api_session.is_status_ok(response.status_code)182microvm.check_log_message(183"The API server received a Get request "184"on \"/machine-config\"."185)186187# Check that all requests on /mmds are logged without the body.188dummy_json = {189'latest': {190'meta-data': {191'ami-id': 'dummy'192}193}194}195response = microvm.mmds.put(json=dummy_json)196assert microvm.api_session.is_status_no_content(response.status_code)197microvm.check_log_message(198"The API server received a Put request on \"/mmds\"."199)200201response = microvm.mmds.patch(json=dummy_json)202assert microvm.api_session.is_status_no_content(response.status_code)203microvm.check_log_message(204"The API server received a Patch request on \"/mmds\"."205)206207response = microvm.mmds.get()208assert microvm.api_session.is_status_ok(response.status_code)209microvm.check_log_message(210"The API server received a Get request on \"/mmds\"."211)212213# Check that the fault message return by the client is also logged in the214# FIFO.215response = microvm.boot.put(216kernel_image_path="inexistent_path"217)218assert microvm.api_session.is_status_bad_request(response.status_code)219fault_message = "The kernel file cannot be opened: No such file or " \220"directory (os error 2)"221assert fault_message in response.text222microvm.check_log_message("Received Error. "223"Status code: 400 Bad Request. "224"Message: {}".format(fault_message))225226227# pylint: disable=W0102228def _test_log_config(229microvm,230log_level='Info',231show_level=True,232show_origin=True233):234"""Exercises different scenarios for testing the logging config."""235microvm.spawn(create_logger=False)236237# Configure logging.238log_fifo_path = os.path.join(microvm.path, 'log_fifo')239log_fifo = log_tools.Fifo(log_fifo_path)240response = microvm.logger.put(241log_path=microvm.create_jailed_resource(log_fifo.path),242level=log_level,243show_level=show_level,244show_log_origin=show_origin245)246assert microvm.api_session.is_status_no_content(response.status_code)247248microvm.start_console_logger(log_fifo)249250microvm.basic_config()251microvm.start()252253lines = microvm.log_data.splitlines()254for idx, line in enumerate(lines):255if idx == 0:256assert line.startswith("Running Firecracker")257continue258check_log_message_format(259line,260microvm.id,261log_level,262show_level,263show_origin264)265266267