XCMetrics Documentation

repository·main·Indexed 22 days ago

https://github.com/spotify/xcmetrics

XCMetrics is a tool for collecting and monitoring Xcode build metrics, including build times, warnings, and errors, to improve developer productivity and code health. Built on XCLogParser, it provides capabilities for build time monitoring, code health diagnosis, and extensibility via custom plugins. The system includes a backend supporting single or multi-instance deployment with PostgreSQL and Redis, and an optional Backstage plugin for visual analysis.

Tokens
6K
Snippets
18
Records
28
Agent score
73%

What's inside XCMetrics

  1. Overview of XCMetrics

    main

    XCMetrics is a tool designed to collect Xcode build metrics to improve developer productivity. It is built on top of XCLogParser, which parses Xcode and xcodebuild logs in the xcactivitylog format.

    Key capabilities include:

    • Build Time Monitoring: Track build durations and identify targets that take the longest to compile.
    • Code Health: Collect warnings and errors to diagnose build problems in real-time.
    • Extensibility: Build custom plugins to attach metadata to builds, such as version control information or thermal throttling data.
  2. How XCMetrics manages build logs and caching

    main

    XCMetrics operates by fetching logs from Xcode's DerivedData directory, copying them to a local cache to avoid interfering with Xcode, and uploading them to a backend service.

    Cache Directory Structure

    Logs are stored in ~/Library/Caches/xcmetrics. The directory is namespaced by project to allow multiple projects to coexist on the same machine without conflicts.

    Directory Layout Example:

    XCMetrics/
    ├── Project1/
    │   ├── 0A391ECA-8B35-4E81-865E-FB6D43861384.xcactivitylog
    │   ├── 8F069C22-27FA-4479-AF3C-9677677FC20D_UPLOADED.xcactivitylog
    │   └── requests/
    │       └── 814B2B39-1E50-4953-992C-AE94982D5B9A
    └── Project2/
        └── 0BBA9976-4EBB-484F-A276-C97A62AB90F2.xcactivitylog

    Log Lifecycle and Upload States

    • New Logs: Copied from Xcode's Logs/Build/ directory to the project-specific cache directory.
    • Successful Uploads: Once a log is successfully uploaded, _UPLOADED is appended to the filename (e.g., [UUID]_UPLOADED.xcactivitylog) to track processed logs.
    • Failed Uploads (Retry Mechanism): If the backend is unreachable, the log is renamed with _UPLOADED, and the request (containing the log and collected metadata) is saved as a binary object in the requests/ directory. XCMetrics automatically retries these requests during the next execution.
  3. Enable scheduled jobs for XCMetrics Backstage

    main

    The Backstage plugin requires aggregated data that is computed daily. To enable this, you must configure your Backend deployment to use Vapor's Scheduled Jobs support by following these two steps:

    1. Start the backend using the --scheduled flag.
    2. Set the environment variable XCMETRICS_SCHEDULE_STATISTICS_JOBS to 1.

    Warning: Do not run scheduled jobs on multiple backend instances simultaneously. Running the same job in multiple instances can cause data corruption or computation issues. It is recommended to designate a single instance to handle the scheduled jobs.

    XCMETRICS_SCHEDULE_STATISTICS_JOBS=1 ./XCMetricsBackend queues --scheduled --env production
  4. Verify XCMetrics client data ingestion locally

    main

    To test that your Xcode project is correctly sending data to your local backend:

    1. Configure your Xcode project's XCMetrics post-build action. Ensure the --serviceURL parameter points to your local instance: --serviceURL http://localhost:8080/v1/metrics
    2. Build the Xcode project to trigger the data upload.
    3. Inspect the data in the Postgres database (running on localhost:5432).
    4. Use a Postgres client (like Postico) to check the builds table.

    Refer to docker-compose.yml for the specific database name, default user, and password.

  5. Deploy XCMetrics in Single Instance mode

    main

    Single instance deployment is the simplest method. In this mode, the Endpoints and the Job run in the same process.

    Key characteristics:

    • No Cloud Storage required: The Endpoint controller stores log files on local disk, and the Job reads them from the same machine.
    • Performance limits: Parallel log processing is limited by the number of CPU cores and the database connection pool size. The maximum parallel logs processed is number of cores * connections per pool. By default, there are 10 connections per pool.
    • Deployment examples: Kubernetes files for this scenario are available in DeploymentExamples/SingleInstance.
  6. Deploy XCMetrics in Multi-Instance mode

    main

    Multi-instance deployment increases fault tolerance and performance by separating the Endpoints (for uploading logs) from the Jobs (for parsing logs). This is recommended for high-volume environments.

    Requirements for Multi-Instance:

    1. Disable same-instance jobs: Set XCMETRICS_START_JOBS_SAME_INSTANCE="0".
    2. Cloud Storage: Since Jobs and Endpoints run on different machines, logs must be stored in a shared cloud repository instead of local disk.

    Amazon S3 Configuration

    Set XCMETRICS_USE_S3_REPOSITORY="1" and provide:

    • XCMETRICS_S3_BUCKET: The name of your S3 bucket.
    • XCMETRICS_S3_REGION: The AWS region.
    • AWS_ACCESS_KEY_ID: IAM User Access Key.
    • AWS_SECRET_ACCESS_KEY: IAM User Secret Key.

    Google Cloud Storage (GCS) Configuration

    Set XCMETRICS_USE_GCS_REPOSITORY="1" and provide:

    • XCMETRICS_GOOGLE_PROJECT: The Google Project ID.
    • GOOGLE_APPLICATION_CREDENTIALS: Path to the .json service account credentials file.
    • XCMETRICS_GCS_BUCKET: The name of your GCS bucket.

    Deployment examples: Kubernetes files for this scenario are available in DeploymentExamples/MultiInstances.

  7. Setup XCMetrics with Google Cloud SQL

    main

    To use Google Cloud SQL (Managed PostgreSQL) with XCMetrics, follow these steps:

    1. Create the Database and User

    Connect to your Cloud SQL instance via Cloud Shell and run the following SQL to initialize the XCMetrics environment:

    CREATE DATABASE xcmetrics;
    CREATE USER xcmetrics WITH ENCRYPTED PASSWORD 'mypassword';
    GRANT ALL PRIVILEGES ON DATABASE xcmetrics to xcmetrics;

    2. Configure Permissions

    The Google Service Account used by XCMetrics requires the following IAM roles:

    • Cloud SQL Client
    • Storage Admin

    3. Connect from GKE or Local

    • Local: Use the Cloud SQL Proxy to connect from your computer.
    • GKE: To connect from Google Kubernetes Engine, you must create a Kubernetes Secret for the password and set up Cloud SQL as a sidecar container.
  8. Deploy XCMetrics to Google Cloud Run

    main

    Cloud Run is a quick option that scales to zero when not in use. Because Cloud Run instances can be killed during idle periods, you cannot reliably run asynchronous jobs.

    Important Configuration for Cloud Run:

    1. Disable Async Jobs: Set XCMETRICS_USE_ASYNC_LOG_PROCESSING="0". This forces the endpoint to process the log synchronously before responding, which increases response time but ensures reliability.
    2. Cloud SQL Connection: Cloud Run uses Unix Sockets for Cloud SQL. Set XCMETRICS_USE_CLOUDSQL_SOCKET="1" and provide XCMETRICS_CLOUDSQL_CONNECTION_NAME (e.g., my_project:gcp_region:cloudql_instance_name).
    3. Client Configuration: You must update your Xcode PostAction to point to the metrics-sync endpoint.

    Required Environment Variables:

    • XCMETRICS_USE_ASYNC_LOG_PROCESSING="0"
    • XCMETRICS_USE_CLOUDSQL_SOCKET="1"
    • XCMETRICS_CLOUDSQL_CONNECTION_NAME
    • DB_NAME
    • DB_USER
    • DB_PASSWORD (can be managed via Cloud Run Secrets)
    # Update your Xcode PostAction to use the metrics-sync endpoint
    ${SRCROOT}/../../XCMetricsLauncher ${SRCROOT}/../../.build/release/XCMetrics --name BasicApp --buildDir ${BUILD_DIR} --serviceURL https://yourservice.com/v1/metrics-sync
  9. Run the XCMetrics backend from Xcode

    main

    To run the backend directly from Xcode, you must first ensure the required Redis and Postgresql dependencies are running. Use the provided docker-compose.yml file for this.

    1. Start the dependencies from the command line:
      docker-compose up -d
    2. In Xcode, select the **XCMetricsBackend** schema.
    3. Run the schema (ensure any `migrate` arguments are removed for a standard run).
    
    **Note:** When finished, stop the Docker instances using `docker-compose stop` to free up resources.
    
  10. Verify XCMetrics GKE Deployment

    main

    After deploying to GKE, verify the services are running and the backend is responsive.

    1. Check Services: Run kubectl get services to find the EXTERNAL-IP for the xcmetrics-server (which should be of type LoadBalancer).

    2. Test Endpoint: Use curl to hit the /v1/build endpoint using the external IP found in the previous step:

    curl -i http://<external-ip>/v1/build

    A successful response looks like:

    {"metadata":{"total":0,"page":1,"per":10},"items":[]}
    1. Client Configuration: Use the external IP in your XCMetrics client by passing the --serviceURL flag. For example:

    --serviceURL http://<external-ip>/v1/metrics

    # Check services
    kubectl get services
    
    # Verify backend
    curl -i http://<external-ip>/v1/build