blob: 639382a296b69b77562966ef18e00cf797e4caa2 [file] [log] [blame]
Aravind Vasudevan8c35d942023-07-26 19:16:59 +00001# Copyright (C) 2023 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Logic for printing user-friendly logs in repo."""
16
17import logging
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000018
19from color import Coloring
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000020from error import RepoExitError
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000021
Mike Frysinger64477332023-08-21 21:20:32 -040022
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000023SEPARATOR = "=" * 80
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000024MAX_PRINT_ERRORS = 5
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000025
26
Aravind Vasudevan712e62b2023-09-06 17:25:58 +000027class _ConfigMock:
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000028 """Default coloring config to use when Logging.config is not set."""
29
30 def __init__(self):
31 self.default_values = {"color.ui": "auto"}
32
33 def GetString(self, x):
34 return self.default_values.get(x, None)
35
36
Aravind Vasudevan712e62b2023-09-06 17:25:58 +000037class _LogColoring(Coloring):
38 """Coloring outstream for logging."""
39
40 def __init__(self, config):
41 super().__init__(config, "logs")
Shik Chen9bf82362024-07-01 18:51:33 +080042 self.error = self.nofmt_colorer("error", fg="red")
43 self.warning = self.nofmt_colorer("warn", fg="yellow")
Aravind Vasudevan712e62b2023-09-06 17:25:58 +000044 self.levelMap = {
45 "WARNING": self.warning,
46 "ERROR": self.error,
47 }
48
49
50class _LogColoringFormatter(logging.Formatter):
51 """Coloring formatter for logging."""
52
53 def __init__(self, config=None, *args, **kwargs):
54 self.config = config if config else _ConfigMock()
55 self.colorer = _LogColoring(self.config)
56 super().__init__(*args, **kwargs)
57
58 def format(self, record):
59 """Formats |record| with color."""
60 msg = super().format(record)
61 colorer = self.colorer.levelMap.get(record.levelname)
62 return msg if not colorer else colorer(msg)
63
64
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000065class RepoLogger(logging.Logger):
66 """Repo Logging Module."""
67
Aravind Vasudevane914ec22023-08-31 20:57:31 +000068 def __init__(self, name: str, config=None, **kwargs):
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000069 super().__init__(name, **kwargs)
Aravind Vasudevan712e62b2023-09-06 17:25:58 +000070 handler = logging.StreamHandler()
71 handler.setFormatter(_LogColoringFormatter(config))
72 self.addHandler(handler)
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000073
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000074 def log_aggregated_errors(self, err: RepoExitError):
Aravind Vasudevan8c35d942023-07-26 19:16:59 +000075 """Print all aggregated logs."""
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000076 self.error(SEPARATOR)
77
78 if not err.aggregate_errors:
79 self.error("Repo command failed: %s", type(err).__name__)
Josh Bartel6d821122023-11-10 15:49:42 -060080 self.error("\t%s", str(err))
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000081 return
82
83 self.error(
84 "Repo command failed due to the following `%s` errors:",
85 type(err).__name__,
86 )
87 self.error(
88 "\n".join(str(e) for e in err.aggregate_errors[:MAX_PRINT_ERRORS])
89 )
90
91 diff = len(err.aggregate_errors) - MAX_PRINT_ERRORS
Aravind Vasudevan83c66ec2023-09-28 19:06:59 +000092 if diff > 0:
Aravind Vasudevanb8fd1922023-09-14 22:54:04 +000093 self.error("+%d additional errors...", diff)