enable telemetry for frontend package download subprocess (#3270)

This commit is contained in:
Martin Xu 2024-05-10 10:17:10 -07:00 committed by GitHub
parent 0238ee96df
commit 4e959694a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 62 additions and 9 deletions

View File

@ -848,6 +848,8 @@ def install_frontend_packages(packages: set[str], config: Config):
processes.run_process_with_fallback(
[get_install_package_manager(), "install"], # type: ignore
fallback=fallback_command,
analytics_enabled=True,
error_filter_fn=lambda output: "404" in output,
show_status_message="Installing base frontend packages",
cwd=constants.Dirs.WEB,
shell=constants.IS_WINDOWS,
@ -863,6 +865,8 @@ def install_frontend_packages(packages: set[str], config: Config):
*((config.tailwind or {}).get("plugins", [])),
],
fallback=fallback_command,
analytics_enabled=True,
error_filter_fn=lambda output: "404" in output,
show_status_message="Installing tailwind",
cwd=constants.Dirs.WEB,
shell=constants.IS_WINDOWS,
@ -873,6 +877,8 @@ def install_frontend_packages(packages: set[str], config: Config):
processes.run_process_with_fallback(
[get_install_package_manager(), "add", *packages],
fallback=fallback_command,
analytics_enabled=True,
error_filter_fn=lambda output: "404" in output,
show_status_message="Installing frontend packages from config and components",
cwd=constants.Dirs.WEB,
shell=constants.IS_WINDOWS,

View File

@ -211,6 +211,8 @@ def stream_logs(
process: subprocess.Popen,
progress=None,
suppress_errors: bool = False,
analytics_enabled: bool = False,
error_filter_fn: Callable[[str], bool] | None = None,
):
"""Stream the logs for a process.
@ -219,6 +221,8 @@ def stream_logs(
process: The process.
progress: The ongoing progress bar if one is being used.
suppress_errors: If True, do not exit if errors are encountered (for fallback).
analytics_enabled: Whether analytics are enabled for this command.
error_filter_fn: A function that takes a line of output and returns True if the line should be considered an error, False otherwise. If None, all lines are considered errors.
Yields:
The lines of the process output.
@ -226,6 +230,8 @@ def stream_logs(
Raises:
Exit: If the process failed.
"""
from reflex.utils import telemetry
# Store the tail of the logs.
logs = collections.deque(maxlen=512)
with process:
@ -246,6 +252,16 @@ def stream_logs(
console.error(f"{message} failed with exit code {process.returncode}")
for line in logs:
console.error(line, end="")
if analytics_enabled:
error_lines = [
line.strip()
for line in logs
if error_filter_fn is None or error_filter_fn(line)
]
max_error_lines = 20
telemetry.send(
"error", context=message, detail=error_lines[:max_error_lines]
)
console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
raise typer.Exit(1)
@ -261,16 +277,30 @@ def show_logs(message: str, process: subprocess.Popen):
pass
def show_status(message: str, process: subprocess.Popen, suppress_errors: bool = False):
def show_status(
message: str,
process: subprocess.Popen,
suppress_errors: bool = False,
analytics_enabled: bool = False,
error_filter_fn: Callable[[str], bool] | None = None,
):
"""Show the status of a process.
Args:
message: The initial message to display.
process: The process.
suppress_errors: If True, do not exit if errors are encountered (for fallback).
analytics_enabled: Whether analytics are enabled for this command.
error_filter_fn: A function that takes a line of output and returns True if the line should be considered an error, False otherwise. If None, all lines are considered errors.
"""
with console.status(message) as status:
for line in stream_logs(message, process, suppress_errors=suppress_errors):
for line in stream_logs(
message,
process,
suppress_errors=suppress_errors,
analytics_enabled=analytics_enabled,
error_filter_fn=error_filter_fn,
):
status.update(f"{message} {line}")
@ -319,19 +349,34 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
return command
def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwargs):
def run_process_with_fallback(
args,
*,
show_status_message,
fallback=None,
analytics_enabled: bool = False,
error_filter_fn: Callable[[str], bool] | None = None,
**kwargs,
):
"""Run subprocess and retry using fallback command if initial command fails.
Args:
args: A string, or a sequence of program arguments.
show_status_message: The status message to be displayed in the console.
fallback: The fallback command to run.
analytics_enabled: Whether analytics are enabled for this command.
error_filter_fn: A function that takes a line of output and returns True if the line should be considered an error, False otherwise. If None, all lines are considered errors.
kwargs: Kwargs to pass to new_process function.
"""
process = new_process(get_command_with_loglevel(args), **kwargs)
if fallback is None:
# No fallback given, or this _is_ the fallback command.
show_status(show_status_message, process)
show_status(
show_status_message,
process,
analytics_enabled=analytics_enabled,
error_filter_fn=error_filter_fn,
)
else:
# Suppress errors for initial command, because we will try to fallback
show_status(show_status_message, process, suppress_errors=True)
@ -345,6 +390,8 @@ def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwa
fallback_args,
show_status_message=show_status_message,
fallback=None,
analytics_enabled=analytics_enabled,
error_filter_fn=error_filter_fn,
**kwargs,
)

View File

@ -126,6 +126,10 @@ def _prepare_event(event: str, **kwargs) -> dict:
cpuinfo = get_cpu_info()
additional_keys = ["template", "context", "detail"]
additional_fields = {
key: value for key in additional_keys if (value := kwargs.get(key)) is not None
}
return {
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
"event": event,
@ -139,11 +143,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
"cpu_count": get_cpu_count(),
"memory": get_memory(),
"cpu_info": dict(cpuinfo) if cpuinfo else {},
**(
{"template": template}
if (template := kwargs.get("template")) is not None
else {}
),
**additional_fields,
},
"timestamp": stamp,
}