浏览代码

Add two metrics to track

Alek Petuskey 10 月之前
父节点
当前提交
05442a4aca

+ 16 - 7
reflex/app_module_for_backend.py

@@ -4,25 +4,34 @@ Only the app attribute is explicitly exposed.
 
 from concurrent.futures import ThreadPoolExecutor
 
+import time
 from reflex import constants
-from reflex.utils import telemetry
+
 from reflex.utils.exec import is_prod_mode
 from reflex.utils.prerequisites import get_app
 
 if constants.CompileVars.APP != "app":
     raise AssertionError("unexpected variable name for 'app'")
 
-telemetry.send("compile")
 app_module = get_app(reload=False)
 app = getattr(app_module, constants.CompileVars.APP)
 # 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).
 app._apply_decorated_pages()
+start_time = time.perf_counter()
+
+def compile_callback(f):
+    from reflex.utils import telemetry
+    try:
+        # Force background compile errors to print eagerly
+        f.result()
+    finally:
+        telemetry.send("test-compile", duration=time.perf_counter()- start_time)
+        del telemetry
+
 compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
-compile_future.add_done_callback(
-    # Force background compile errors to print eagerly
-    lambda f: f.result()
-)
+compile_future.add_done_callback(compile_callback)
+
 # Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted.
 if is_prod_mode():
     compile_future.result()
@@ -32,6 +41,6 @@ del app_module
 del compile_future
 del get_app
 del is_prod_mode
-del telemetry
+
 del constants
 del ThreadPoolExecutor

+ 1 - 0
reflex/components/el/elements/metadata.py

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

+ 11 - 2
reflex/reflex.py

@@ -8,6 +8,7 @@ import webbrowser
 from pathlib import Path
 from typing import List, Optional
 
+import time
 import typer
 import typer.core
 from reflex_cli.deployments import deployments_cli
@@ -108,8 +109,13 @@ def _init(
             raise typer.Exit(2)
         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.
-    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 generation_hash:
@@ -129,7 +135,10 @@ def _init(
     # Finish initializing the app.
     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()
 def init(
     name: str = typer.Option(

+ 3 - 10
reflex/utils/prerequisites.py

@@ -1419,7 +1419,7 @@ def create_config_init_app_from_remote_template(
     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.
 
     Args:
@@ -1429,12 +1429,8 @@ def initialize_app(app_name: str, template: str | None = None):
     Raises:
         Exit: If template is directly provided in the command flag and is invalid.
     """
-    # Local imports to avoid circular imports.
-    from reflex.utils import telemetry
-
-    # Check if the app is already initialized.
-    if os.path.exists(constants.Config.FILE):
-        telemetry.send("reinit")
+    # Check if the app is already initialized. If so, we don't need to init.
+    if reinit:
         return
 
     # Get the available templates
@@ -1473,9 +1469,6 @@ def initialize_app(app_name: str, template: str | None = None):
             template_url=template_url,
         )
 
-    telemetry.send("init", template=template)
-
-
 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.
 

+ 19 - 3
reflex/utils/telemetry.py

@@ -6,7 +6,7 @@ import asyncio
 import multiprocessing
 import platform
 import warnings
-
+import os 
 try:
     from datetime import UTC, datetime
 except ImportError:
@@ -69,7 +69,7 @@ def get_cpu_count() -> int:
     """
     return multiprocessing.cpu_count()
 
-
+ 
 def get_memory() -> int:
     """Get the total memory in MB.
 
@@ -80,6 +80,21 @@ def get_memory() -> int:
         return psutil.virtual_memory().total >> 20
     except ValueError:  # needed to pass ubuntu test
         return 0
+    
+def get_folder_size(folder: str) -> int:
+    """Get the total size of a folder in bytes, ignoring 'node_modules' folder.
+
+    Args:
+        folder: The path to the folder.
+
+    Returns:
+        The total size of the folder in bytes.
+    """
+    total_files = 0
+    for dirpath, dirnames, filenames in os.walk(folder):
+        total_files += len(filenames)
+    return total_files
+
 
 
 def _raise_on_missing_project_hash() -> bool:
@@ -128,7 +143,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
 
     cpuinfo = get_cpu_info()
 
-    additional_keys = ["template", "context", "detail"]
+    additional_keys = ["template", "context", "detail", "duration"]
     additional_fields = {
         key: value for key in additional_keys if (value := kwargs.get(key)) is not None
     }
@@ -145,6 +160,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
             "cpu_count": get_cpu_count(),
             "memory": get_memory(),
             "cpu_info": dict(cpuinfo) if cpuinfo else {},
+            "pages_count": get_folder_size(".web/pages") if event == "test-compile" or event == "run-dev" else None,
             **additional_fields,
         },
         "timestamp": stamp,