[REF-2774] Send runtime error in telemetry (#3276)
This commit is contained in:
parent
b95e02a805
commit
aa2cf80f70
@ -1067,51 +1067,61 @@ async def process(
|
||||
headers: The client headers.
|
||||
client_ip: The client_ip.
|
||||
|
||||
Raises:
|
||||
ReflexError: If a reflex specific error occurs during processing the event.
|
||||
|
||||
Yields:
|
||||
The state updates after processing the event.
|
||||
"""
|
||||
# Add request data to the state.
|
||||
router_data = event.router_data
|
||||
router_data.update(
|
||||
{
|
||||
constants.RouteVar.QUERY: format.format_query_params(event.router_data),
|
||||
constants.RouteVar.CLIENT_TOKEN: event.token,
|
||||
constants.RouteVar.SESSION_ID: sid,
|
||||
constants.RouteVar.HEADERS: headers,
|
||||
constants.RouteVar.CLIENT_IP: client_ip,
|
||||
}
|
||||
)
|
||||
# Get the state for the session exclusively.
|
||||
async with app.state_manager.modify_state(event.substate_token) as state:
|
||||
# re-assign only when the value is different
|
||||
if state.router_data != router_data:
|
||||
# assignment will recurse into substates and force recalculation of
|
||||
# dependent ComputedVar (dynamic route variables)
|
||||
state.router_data = router_data
|
||||
state.router = RouterData(router_data)
|
||||
from reflex.utils import telemetry
|
||||
from reflex.utils.exceptions import ReflexError
|
||||
|
||||
# Preprocess the event.
|
||||
update = await app._preprocess(state, event)
|
||||
try:
|
||||
# Add request data to the state.
|
||||
router_data = event.router_data
|
||||
router_data.update(
|
||||
{
|
||||
constants.RouteVar.QUERY: format.format_query_params(event.router_data),
|
||||
constants.RouteVar.CLIENT_TOKEN: event.token,
|
||||
constants.RouteVar.SESSION_ID: sid,
|
||||
constants.RouteVar.HEADERS: headers,
|
||||
constants.RouteVar.CLIENT_IP: client_ip,
|
||||
}
|
||||
)
|
||||
# Get the state for the session exclusively.
|
||||
async with app.state_manager.modify_state(event.substate_token) as state:
|
||||
# re-assign only when the value is different
|
||||
if state.router_data != router_data:
|
||||
# assignment will recurse into substates and force recalculation of
|
||||
# dependent ComputedVar (dynamic route variables)
|
||||
state.router_data = router_data
|
||||
state.router = RouterData(router_data)
|
||||
|
||||
# If there was an update, yield it.
|
||||
if update is not None:
|
||||
yield update
|
||||
# Preprocess the event.
|
||||
update = await app._preprocess(state, event)
|
||||
|
||||
# Only process the event if there is no update.
|
||||
else:
|
||||
if app._process_background(state, event) is not None:
|
||||
# `final=True` allows the frontend send more events immediately.
|
||||
yield StateUpdate(final=True)
|
||||
return
|
||||
|
||||
# Process the event synchronously.
|
||||
async for update in state._process(event):
|
||||
# Postprocess the event.
|
||||
update = await app._postprocess(state, event, update)
|
||||
|
||||
# Yield the update.
|
||||
# If there was an update, yield it.
|
||||
if update is not None:
|
||||
yield update
|
||||
|
||||
# Only process the event if there is no update.
|
||||
else:
|
||||
if app._process_background(state, event) is not None:
|
||||
# `final=True` allows the frontend send more events immediately.
|
||||
yield StateUpdate(final=True)
|
||||
return
|
||||
|
||||
# Process the event synchronously.
|
||||
async for update in state._process(event):
|
||||
# Postprocess the event.
|
||||
update = await app._postprocess(state, event, update)
|
||||
|
||||
# Yield the update.
|
||||
yield update
|
||||
except ReflexError as ex:
|
||||
telemetry.send("error", context="backend", detail=str(ex))
|
||||
raise
|
||||
|
||||
|
||||
async def ping() -> str:
|
||||
"""Test API endpoint.
|
||||
|
@ -1462,6 +1462,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
Yields:
|
||||
StateUpdate object
|
||||
"""
|
||||
from reflex.utils import telemetry
|
||||
from reflex.utils.exceptions import ReflexError
|
||||
|
||||
# Get the function to process the event.
|
||||
fn = functools.partial(handler.fn, state)
|
||||
|
||||
@ -1497,9 +1500,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
yield state._as_state_update(handler, events, final=True)
|
||||
|
||||
# If an error occurs, throw a window alert.
|
||||
except Exception:
|
||||
except Exception as ex:
|
||||
error = traceback.format_exc()
|
||||
print(error)
|
||||
if isinstance(ex, ReflexError):
|
||||
telemetry.send("error", context="backend", detail=str(ex))
|
||||
yield state._as_state_update(
|
||||
handler,
|
||||
window_alert("An error occurred. See logs for details."),
|
||||
|
@ -856,7 +856,6 @@ def install_frontend_packages(packages: set[str], config: Config):
|
||||
[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,
|
||||
@ -873,7 +872,6 @@ def install_frontend_packages(packages: set[str], config: Config):
|
||||
],
|
||||
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,
|
||||
@ -885,7 +883,6 @@ def install_frontend_packages(packages: set[str], config: Config):
|
||||
[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,
|
||||
|
@ -212,7 +212,6 @@ def stream_logs(
|
||||
progress=None,
|
||||
suppress_errors: bool = False,
|
||||
analytics_enabled: bool = False,
|
||||
error_filter_fn: Callable[[str], bool] | None = None,
|
||||
):
|
||||
"""Stream the logs for a process.
|
||||
|
||||
@ -222,7 +221,6 @@ def stream_logs(
|
||||
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.
|
||||
@ -253,15 +251,7 @@ def stream_logs(
|
||||
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]
|
||||
)
|
||||
telemetry.send("error", context=message)
|
||||
console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
|
||||
raise typer.Exit(1)
|
||||
|
||||
@ -282,7 +272,6 @@ def show_status(
|
||||
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.
|
||||
|
||||
@ -291,7 +280,6 @@ def show_status(
|
||||
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(
|
||||
@ -299,7 +287,6 @@ def show_status(
|
||||
process,
|
||||
suppress_errors=suppress_errors,
|
||||
analytics_enabled=analytics_enabled,
|
||||
error_filter_fn=error_filter_fn,
|
||||
):
|
||||
status.update(f"{message} {line}")
|
||||
|
||||
@ -355,7 +342,6 @@ def run_process_with_fallback(
|
||||
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.
|
||||
@ -365,7 +351,6 @@ def run_process_with_fallback(
|
||||
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)
|
||||
@ -375,7 +360,6 @@ def run_process_with_fallback(
|
||||
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
|
||||
@ -391,7 +375,6 @@ def run_process_with_fallback(
|
||||
show_status_message=show_status_message,
|
||||
fallback=None,
|
||||
analytics_enabled=analytics_enabled,
|
||||
error_filter_fn=error_filter_fn,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user