samcli/lib/init/template_modifiers/structured_logging_template_modifier.py (65 lines of code) (raw):

""" Class used to parse and update template when structured logging is enabled """ import logging from typing import Any from ruamel.yaml import YAML from ruamel.yaml.comments import CommentedMap from ruamel.yaml.representer import RoundTripRepresenter from samcli.lib.init.template_modifiers.cli_template_modifier import TemplateModifier LOG = logging.getLogger(__name__) class StructuredLoggingTemplateModifier(TemplateModifier): GLOBALS = "Globals" RESOURCE = "Resources" FUNCTION = "Function" LOGGING_CONFIG = "LoggingConfig" JSON_LOGFORMAT = {"LogFormat": "JSON"} DOC_LINK = ( "https://docs.aws.amazon.com/serverless-application-model/latest/" "developerguide/sam-resource-function.html#sam-function-loggingconfig" ) COMMENT = ( "More info about Globals: " "https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst\n" ) MESSAGE = ( "You can add LoggingConfig parameters such as the Logformat, " "Log Group, and SystemLogLevel or ApplicationLogLevel. " f"Learn more here {DOC_LINK}.\n" ) # set ignore aliases to true. This configuration avoids usage yaml aliases which is not parsed by CloudFormation. class NonAliasingRTRepresenter(RoundTripRepresenter): def ignore_aliases(self, data): return True def __init__(self, location): self.yaml = YAML() self.yaml.Representer = StructuredLoggingTemplateModifier.NonAliasingRTRepresenter super().__init__(location) def _get_template(self) -> Any: with open(self.template_location) as file: return self.yaml.load(file) def _update_template_fields(self): """ Add new field to SAM template """ if self.template.get(self.GLOBALS): template_globals = self.template.get(self.GLOBALS) function_globals = template_globals.get(self.FUNCTION, {}) if not function_globals: template_globals[self.FUNCTION] = {} template_globals[self.FUNCTION][self.LOGGING_CONFIG] = CommentedMap(self.JSON_LOGFORMAT) template_globals[self.FUNCTION].yaml_set_comment_before_after_key( self.LOGGING_CONFIG, before=self.MESSAGE, indent=4 ) else: self._add_logging_config_with_globals() def _add_logging_config_with_globals(self): """Adds Globals and LoggingConfig fields""" global_section = { self.FUNCTION: {self.LOGGING_CONFIG: self.JSON_LOGFORMAT}, } self.template = CommentedMap(self.template) self.template[self.GLOBALS] = CommentedMap(global_section) self.template[self.GLOBALS].yaml_set_comment_before_after_key(self.LOGGING_CONFIG, before=self.MESSAGE) self.template.yaml_set_comment_before_after_key(self.GLOBALS, before=self.COMMENT) def _print_sanity_check_error(self): message = ( "Warning: Unable to add LoggingConfig to the project. " "To learn more about LoggingConfig visit {self.DOC_LINK}" ) LOG.warning(message) def _write(self, template: list): """ write generated template into SAM template Parameters ---------- template : list array with updated template data """ with open(self.template_location, "w") as file: self.yaml.dump(self.template, file)