Compare commits

...

7 Commits

Author SHA1 Message Date
Alek Petuskey
855dc932a6 Comment as public keyt 2024-07-31 14:42:36 -07:00
Alek Petuskey
230474376c Better name for helper 2024-07-31 14:41:50 -07:00
Alek Petuskey
46c6b80e4c more accurate doc string 2024-07-31 14:38:04 -07:00
Alek Petuskey
043f6dce59 test-compile to compile 2024-07-31 14:37:13 -07:00
Alek Petuskey
07f9844cb0 test event to regular event 2024-07-31 14:36:15 -07:00
Alek Petuskey
7d0d72c0df Clean up doc string 2024-07-31 14:34:26 -07:00
Alek Petuskey
05442a4aca Add two metrics to track 2024-07-31 14:04:51 -07:00
5 changed files with 58 additions and 18 deletions

View File

@ -2,6 +2,7 @@
Only the app attribute is explicitly exposed. Only the app attribute is explicitly exposed.
""" """
import time
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from reflex import constants from reflex import constants
@ -12,17 +13,17 @@ from reflex.utils.prerequisites import get_app
if constants.CompileVars.APP != "app": if constants.CompileVars.APP != "app":
raise AssertionError("unexpected variable name for 'app'") raise AssertionError("unexpected variable name for 'app'")
telemetry.send("compile")
app_module = get_app(reload=False) app_module = get_app(reload=False)
app = getattr(app_module, constants.CompileVars.APP) app = getattr(app_module, constants.CompileVars.APP)
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages # For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
# before compiling the app in a thread to avoid event loop error (REF-2172). # before compiling the app in a thread to avoid event loop error (REF-2172).
app._apply_decorated_pages() app._apply_decorated_pages()
start_time = time.perf_counter()
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile) compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
compile_future.add_done_callback( compile_future.add_done_callback(lambda f: telemetry.compile_callback(f, start_time))
# Force background compile errors to print eagerly
lambda f: f.result()
)
# Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted. # Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted.
if is_prod_mode(): if is_prod_mode():
compile_future.result() compile_future.result()
@ -32,6 +33,5 @@ del app_module
del compile_future del compile_future
del get_app del get_app
del is_prod_mode del is_prod_mode
del telemetry
del constants del constants
del ThreadPoolExecutor del ThreadPoolExecutor

View File

@ -44,6 +44,7 @@ class Meta(BaseHTML): # Inherits common attributes from BaseHTML
"""Display the meta element.""" """Display the meta element."""
tag = "meta" tag = "meta"
char_set: Var[Union[str, int, bool]] char_set: Var[Union[str, int, bool]]
content: Var[Union[str, int, bool]] content: Var[Union[str, int, bool]]
http_equiv: Var[Union[str, int, bool]] http_equiv: Var[Union[str, int, bool]]

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import atexit import atexit
import os import os
import time
import webbrowser import webbrowser
from pathlib import Path from pathlib import Path
from typing import List, Optional from typing import List, Optional
@ -108,8 +109,13 @@ def _init(
raise typer.Exit(2) raise typer.Exit(2)
template = constants.Templates.DEFAULT template = constants.Templates.DEFAULT
start_time = time.perf_counter()
# Check if the app is already initialized.
reinit = os.path.exists(constants.Config.FILE)
# Initialize the app. # Initialize the app.
prerequisites.initialize_app(app_name, template) prerequisites.initialize_app(app_name, template, reinit=reinit)
# If a reflex.build generation hash is available, download the code and apply it to the main module. # If a reflex.build generation hash is available, download the code and apply it to the main module.
if generation_hash: if generation_hash:
@ -129,6 +135,10 @@ def _init(
# Finish initializing the app. # Finish initializing the app.
console.success(f"Initialized {app_name}") console.success(f"Initialized {app_name}")
# Post telemetry event
event_type = "reinit" if reinit else "init"
telemetry.send(event_type, duration=time.perf_counter() - start_time)
@cli.command() @cli.command()
def init( def init(

View File

@ -1419,22 +1419,19 @@ def create_config_init_app_from_remote_template(
shutil.rmtree(unzip_dir) shutil.rmtree(unzip_dir)
def initialize_app(app_name: str, template: str | None = None): def initialize_app(app_name: str, template: str | None = None, reinit: bool = False):
"""Initialize the app either from a remote template or a blank app. If the config file exists, it is considered as reinit. """Initialize the app either from a remote template or a blank app. If the config file exists, it is considered as reinit.
Args: Args:
app_name: The name of the app. app_name: The name of the app.
template: The name of the template to use. template: The name of the template to use.
reinit: Whether to reinitialize the app.
Raises: Raises:
Exit: If template is directly provided in the command flag and is invalid. Exit: If template is directly provided in the command flag and is invalid.
""" """
# Local imports to avoid circular imports. # Check if the app is already initialized. If so, we don't need to init.
from reflex.utils import telemetry if reinit:
# Check if the app is already initialized.
if os.path.exists(constants.Config.FILE):
telemetry.send("reinit")
return return
# Get the available templates # Get the available templates
@ -1473,8 +1470,6 @@ def initialize_app(app_name: str, template: str | None = None):
template_url=template_url, template_url=template_url,
) )
telemetry.send("init", template=template)
def initialize_main_module_index_from_generation(app_name: str, generation_hash: str): def initialize_main_module_index_from_generation(app_name: str, generation_hash: str):
"""Overwrite the `index` function in the main module with reflex.build generated code. """Overwrite the `index` function in the main module with reflex.build generated code.

View File

@ -4,7 +4,9 @@ from __future__ import annotations
import asyncio import asyncio
import multiprocessing import multiprocessing
import os
import platform import platform
import time
import warnings import warnings
try: try:
@ -82,6 +84,21 @@ def get_memory() -> int:
return 0 return 0
def get_page_count(folder: str) -> int:
"""Get the total number of files in a folder.
Args:
folder: The path to the folder.
Returns:
The total number of files in the folder.
"""
total_files = 0
for _, _, filenames in os.walk(folder):
total_files += len(filenames)
return total_files
def _raise_on_missing_project_hash() -> bool: def _raise_on_missing_project_hash() -> bool:
"""Check if an error should be raised when project hash is missing. """Check if an error should be raised when project hash is missing.
@ -98,6 +115,20 @@ def _raise_on_missing_project_hash() -> bool:
return True return True
def compile_callback(f, start_time):
"""Callback to send telemetry after compiling the app.
Args:
f: The future object.
start_time: The start time of the compilation.
"""
try:
# Force background compile errors to print eagerly
f.result()
finally:
send("compile", duration=time.perf_counter() - start_time)
def _prepare_event(event: str, **kwargs) -> dict: def _prepare_event(event: str, **kwargs) -> dict:
"""Prepare the event to be sent to the PostHog server. """Prepare the event to be sent to the PostHog server.
@ -128,12 +159,12 @@ def _prepare_event(event: str, **kwargs) -> dict:
cpuinfo = get_cpu_info() cpuinfo = get_cpu_info()
additional_keys = ["template", "context", "detail"] additional_keys = ["template", "context", "detail", "duration"]
additional_fields = { additional_fields = {
key: value for key in additional_keys if (value := kwargs.get(key)) is not None key: value for key in additional_keys if (value := kwargs.get(key)) is not None
} }
return { return {
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb", "api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb", # Public API key
"event": event, "event": event,
"properties": { "properties": {
"distinct_id": installation_id, "distinct_id": installation_id,
@ -145,6 +176,9 @@ def _prepare_event(event: str, **kwargs) -> dict:
"cpu_count": get_cpu_count(), "cpu_count": get_cpu_count(),
"memory": get_memory(), "memory": get_memory(),
"cpu_info": dict(cpuinfo) if cpuinfo else {}, "cpu_info": dict(cpuinfo) if cpuinfo else {},
"pages_count": get_page_count(".web/pages")
if event == "compile" or event == "run-dev"
else None,
**additional_fields, **additional_fields,
}, },
"timestamp": stamp, "timestamp": stamp,