diff --git a/.github/workflows/ci-backup.yml b/.github/workflows/ci-backup.yml new file mode 100644 index 0000000000..ac0735253d --- /dev/null +++ b/.github/workflows/ci-backup.yml @@ -0,0 +1,560 @@ +name: Continuous Integration + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + push: + branches: + - main + - 'release/**' + +permissions: + pull-requests: write + actions: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +env: + BUILD_ARTIFACT_NAME: 'lace-dev-${{ github.sha }}' + +jobs: + prepare: + name: Prepare + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Collect Workflow Telemetry Build Packages + uses: catchpoint/workflow-telemetry-action@v2 + with: + comment_on_pr: false + + - name: Setup Node.js and install dependencies + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Build common + uses: ./.github/actions/build/package + with: + DIR: packages/common + NAME: packages-common + + - name: Build cardano + uses: ./.github/actions/build/package + with: + DIR: packages/cardano + NAME: packages-cardano + + - name: Build translation + uses: ./.github/actions/build/package + with: + DIR: packages/translation + NAME: packages-translation + + - name: Build core + uses: ./.github/actions/build/package + with: + DIR: packages/core + NAME: packages-core + + - name: Build staking + uses: ./.github/actions/build/package + with: + DIR: packages/staking + NAME: packages-staking + + - name: Build nami + uses: ./.github/actions/build/package + with: + DIR: packages/nami + NAME: packages-nami + + - name: Build bitcoin + uses: ./.github/actions/build/package + with: + DIR: packages/bitcoin + NAME: packages-bitcoin + + unitTests: + name: Unit tests + runs-on: ubuntu-22.04 + needs: prepare + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js and install dependencies + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Download packages-common + uses: actions/download-artifact@v4 + with: + name: packages-common + path: packages/common/dist + + - name: Download packages-cardano + uses: actions/download-artifact@v4 + with: + name: packages-cardano + path: packages/cardano/dist + + - name: Download packages-translation + uses: actions/download-artifact@v4 + with: + name: packages-translation + path: packages/translation/dist + + - name: Download packages-core + uses: actions/download-artifact@v4 + with: + name: packages-core + path: packages/core/dist + + - name: Download packages-staking + uses: actions/download-artifact@v4 + with: + name: packages-staking + path: packages/staking/dist + + - name: Download packages-nami + uses: actions/download-artifact@v4 + with: + name: packages-nami + path: packages/nami/dist + + - name: Download packages-bitcoin + uses: actions/download-artifact@v4 + with: + name: packages-bitcoin + path: packages/bitcoin/dist + + - name: Collect Workflow Telemetry Unit Tests + uses: catchpoint/workflow-telemetry-action@v2 + with: + comment_on_pr: false + + - name: Execute unit tests + uses: ./.github/actions/test/unit + + release-pkg: + name: Release package + runs-on: ubuntu-22.04 + needs: prepare + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js and install dependencies + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Download packages-common + uses: actions/download-artifact@v4 + with: + name: packages-common + path: packages/common/dist + + - name: Download packages-cardano + uses: actions/download-artifact@v4 + with: + name: packages-cardano + path: packages/cardano/dist + + - name: Download packages-translation + uses: actions/download-artifact@v4 + with: + name: packages-translation + path: packages/translation/dist + + - name: Download packages-core + uses: actions/download-artifact@v4 + with: + name: packages-core + path: packages/core/dist + + - name: Download packages-staking + uses: actions/download-artifact@v4 + with: + name: packages-staking + path: packages/staking/dist + + - name: Download packages-nami + uses: actions/download-artifact@v4 + with: + name: packages-nami + path: packages/nami/dist + + - name: Download packages-bitcoin + uses: actions/download-artifact@v4 + with: + name: packages-bitcoin + path: packages/bitcoin/dist + + - name: Collect Workflow Telemetry Smoke Tests + uses: catchpoint/workflow-telemetry-action@v2 + with: + comment_on_pr: false + + - name: Build Lace browser extension + uses: ./.github/actions/build/app + with: + BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }} + BLOCKFROST_PROJECT_ID_PREPROD: ${{ secrets.BLOCKFROST_PROJECT_ID_PREPROD }} + BLOCKFROST_PROJECT_ID_PREVIEW: ${{ secrets.BLOCKFROST_PROJECT_ID_PREVIEW }} + MAESTRO_PROJECT_ID_MAINNET: ${{ secrets.MAESTRO_PROJECT_ID_MAINNET }} + MAESTRO_PROJECT_ID_TESTNET: ${{ secrets.MAESTRO_PROJECT_ID_TESTNET }} + DIR: apps/browser-extension-wallet + NAME: lace-browser-extension + LACE_EXTENSION_KEY: ${{ secrets.MANIFEST_PUBLIC_KEY }} + POSTHOG_PRODUCTION_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.POSTHOG_PRODUCTION_TOKEN || '' }} + PRODUCTION_MODE_TRACKING: ${{ startsWith(github.ref, 'refs/heads/release') && 'true' || 'false' }} + BANXA_LACE_URL: ${{ startsWith(github.ref, 'refs/heads/release') && 'https://lacewallet.banxa.com/' }} + SENTRY_AUTH_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_ORG: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_PROJECT || ''}} + SENTRY_ENVIRONMENT: 'production' + DAPP_RADAR_API_KEY: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.DAPP_RADAR_API_KEY || '' }} + + - name: Build Lace Firefox addon + uses: ./.github/actions/build/app + with: + BROWSER_TARGET: 'firefox' + BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }} + BLOCKFROST_PROJECT_ID_PREPROD: ${{ secrets.BLOCKFROST_PROJECT_ID_PREPROD }} + BLOCKFROST_PROJECT_ID_PREVIEW: ${{ secrets.BLOCKFROST_PROJECT_ID_PREVIEW }} + MAESTRO_PROJECT_ID_MAINNET: ${{ secrets.MAESTRO_PROJECT_ID_MAINNET }} + MAESTRO_PROJECT_ID_TESTNET: ${{ secrets.MAESTRO_PROJECT_ID_TESTNET }} + DIR: apps/browser-extension-wallet + NAME: lace-firefox-addon + LACE_EXTENSION_KEY: ${{ secrets.MANIFEST_PUBLIC_KEY }} + POSTHOG_PRODUCTION_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.POSTHOG_PRODUCTION_TOKEN || '' }} + PRODUCTION_MODE_TRACKING: ${{ startsWith(github.ref, 'refs/heads/release') && 'true' || 'false' }} + BANXA_LACE_URL: ${{ startsWith(github.ref, 'refs/heads/release') && 'https://lacewallet.banxa.com/' }} + SENTRY_AUTH_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_ORG: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_PROJECT || ''}} + SENTRY_ENVIRONMENT: 'production' + DAPP_RADAR_API_KEY: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.DAPP_RADAR_API_KEY || '' }} + + build: + name: Build Lace + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build Lace artifact + uses: ./.github/shared/build + with: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + LACE_EXTENSION_KEY: ${{ secrets.MANIFEST_PUBLIC_KEY }} + BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }} + BLOCKFROST_PROJECT_ID_PREPROD: ${{ secrets.BLOCKFROST_PROJECT_ID_PREPROD }} + BLOCKFROST_PROJECT_ID_PREVIEW: ${{ secrets.BLOCKFROST_PROJECT_ID_PREVIEW }} + BLOCKFROST_PROJECT_ID_SANCHONET: ${{ secrets.BLOCKFROST_PROJECT_ID_SANCHONET }} + MAESTRO_PROJECT_ID_MAINNET: ${{ secrets.MAESTRO_PROJECT_ID_MAINNET }} + MAESTRO_PROJECT_ID_TESTNET: ${{ secrets.MAESTRO_PROJECT_ID_TESTNET }} + SENTRY_AUTH_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.SENTRY_AUTH_TOKEN || '' }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_ORG: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_ORG || '' }} + SENTRY_PROJECT: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_PROJECT || ''}} + SENTRY_ENVIRONMENT: 'smoke-tests' + WALLET_POLLING_INTERVAL_IN_SEC: 5 + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: '${{ env.BUILD_ARTIFACT_NAME }}' + path: ./apps/browser-extension-wallet/dist + + smokeTests: + name: Smoke e2e tests + runs-on: ubuntu-22.04 + needs: build + strategy: + fail-fast: false + matrix: + batch: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js and install dependencies + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Download Lace build artifact + uses: actions/download-artifact@v4 + with: + name: '${{ env.BUILD_ARTIFACT_NAME }}' + path: ./apps/browser-extension-wallet/dist + + - name: Execute E2E tests + uses: ./.github/actions/test/e2e + with: + BATCH: ${{ matrix.batch }} + SMOKE_ONLY: true + TEST_DAPP_URL: ${{ secrets.TEST_DAPP_URL }} + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + SERVICE_WORKER_LOGS: true + + processReports: + name: Process smoke e2e test reports + runs-on: ubuntu-22.04 + needs: smokeTests + if: always() + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download all smoke tests artifacts + uses: actions/download-artifact@v4 + with: + path: . + pattern: 'runner-artifacts-*' + merge-multiple: true + + - name: Create allure properties + shell: bash + if: always() + working-directory: ./reports/allure/results + run: | + echo " + branch=${{ github.ref_name }} + browser= 'Chrome' + tags= '@Smoke' + platform=Linux + " > environment.properties + + - name: Convert metrics JSON to Prometheus format + working-directory: './packages/e2e-tests/tools/' + run: | + ./convert_metrics_to_prometheus.sh "${{ github.workflow }}" "${{ github.run_id }}" ../../../metrics + + - name: Publish allure report to S3 + uses: andrcuns/allure-publish-action@v2.9.0 + if: always() + env: + GITHUB_AUTH_TOKEN: ${{ secrets.GH_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.E2E_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.E2E_AWS_SECRET_ACCESS_KEY }} + with: + storageType: s3 + resultsGlob: './reports/allure/results' + bucket: lace-e2e-test-results + prefix: 'smoke/linux/chrome/${{ github.run_number }}' + copyLatest: true + ignoreMissingResults: true + updatePr: comment + baseUrl: 'https://${{ secrets.E2E_REPORTS_USER }}:${{ secrets.E2E_REPORTS_PASSWORD }}@${{ secrets.E2E_REPORTS_URL }}' + + - name: Publish artifacts (logs, reports, screenshots) + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-artifacts + path: | + ./packages/e2e-tests/screenshots + ./packages/e2e-tests/logs + ./packages/e2e-tests/reports + retention-days: 5 + + - run: | + if [[ ${{ needs.smokeTests.result }} == "success" ]]; then + exit 0 + else + exit 1 + fi + + if-core-changed: + name: When core changed + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-22.04 + outputs: + requireChromaticCheck: ${{ steps.diffcheck.outputs.requireChromaticCheck }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - id: diffcheck + run: | + set +e + git diff --quiet ${{ github.event.pull_request.base.sha }}..${{ github.sha }} -- packages/core/** + echo "requireChromaticCheck=$?" >> "$GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + set -e + + chromaticCore: + name: > + Run Chromatic check: Core + runs-on: ubuntu-22.04 + needs: + - prepare + - if-core-changed + + steps: + - name: Checkout repository + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js and install dependencies + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Download packages-common + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-common + path: packages/common/dist + + - name: Download packages-cardano + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-cardano + path: packages/cardano/dist + + - name: Download packages-translation + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-translation + path: packages/translation/dist + + - name: Download packages-core + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-core + path: packages/core/dist + + - name: Chromatic packages-core + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} + uses: ./.github/actions/chromatic + with: + DIR: packages/core + NAME: packages-core + TOKEN: ${{ secrets.CHROMATIC_LACE_CORE_TOKEN }} + + - name: Skip + if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 0 }} + run: echo "Chromatic check for packages/core not needed" + exit 0 + + if-staking-changed: + name: When staking change + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-22.04 + outputs: + requireChromaticCheck: ${{ steps.diffcheck.outputs.requireChromaticCheck }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - id: diffcheck + run: | + set +e + git diff --quiet ${{ github.event.pull_request.base.sha }}..${{ github.sha }} -- packages/staking/** + echo "requireChromaticCheck=$?" >> "$GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + set -e + + chromaticStaking: + name: > + Run Chromatic check: Staking + runs-on: ubuntu-22.04 + needs: + - prepare + - if-staking-changed + + steps: + - name: Checkout repository + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js and install dependencies + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: ./.github/actions/install + with: + WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Download packages-common + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-common + path: packages/common/dist + + - name: Download packages-cardano + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-cardano + path: packages/cardano/dist + + - name: Download packages-translation + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-translation + path: packages/translation/dist + + - name: Download packages-core + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-core + path: packages/core/dist + + - name: Download packages-staking + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: actions/download-artifact@v4 + with: + name: packages-staking + path: packages/staking/dist + + - name: Chromatic packages-staking + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} + uses: ./.github/actions/chromatic + with: + DIR: packages/staking + NAME: packages-staking + TOKEN: ${{ secrets.CHROMATIC_LACE_STAKING_TOKEN }} + + - name: Skip + if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 0 }} + run: echo "Chromatic check for packages/staking not needed" + exit 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faf2eb740a..4b357f70d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,28 +1,49 @@ -name: Continuous Integration +name: Continuous Integration with Datadog on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] push: - branches: - - main - - 'release/**' - -permissions: - pull-requests: write - actions: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + branches: [ main, develop, test/berno_prom_metrics ] + pull_request: + branches: [ main, develop ] env: BUILD_ARTIFACT_NAME: 'lace-dev-${{ github.sha }}' jobs: + datadog-ci: + runs-on: ubuntu-latest + steps: + - name: Send CI metrics to Datadog + run: | + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "Sending CI metrics to Datadog v2..." + response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d '{ + "series": [{ + "metric": "github.ci.pipeline.duration", + "points": [{"timestamp": $(date +%s), "value": ${{ github.run_duration }}}], + "tags": ["service:lace-wallet", "env:ci", "workflow:${{ github.workflow }}", "job:${{ github.job }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}"] + }, { + "metric": "github.ci.pipeline.status", + "points": [{"timestamp": $(date +%s), "value": 1}], + "tags": ["service:lace-wallet", "env:ci", "workflow:${{ github.workflow }}", "job:${{ github.job }}", "status:${{ job.status }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}"] + }, { + "metric": "github.ci.job.duration", + "points": [{"timestamp": $(date +%s), "value": ${{ github.run_duration }}}], + "tags": ["service:lace-wallet", "env:ci", "workflow:${{ github.workflow }}", "job:${{ github.job }}", "runner:ubuntu-latest", "repo:${{ github.repository }}"] + }] + }') + echo "Datadog API response: $response" + else + echo "No DATADOG_API_KEY provided, skipping metrics" + fi + prepare: name: Prepare runs-on: ubuntu-22.04 + needs: [datadog-ci] steps: - name: Checkout repository @@ -83,8 +104,31 @@ jobs: DIR: packages/bitcoin NAME: packages-bitcoin + - name: Send build metrics to Datadog + run: | + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "Sending build metrics to Datadog v2..." + response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d '{ + "series": [{ + "metric": "lace.build.packages", + "points": [{"timestamp": $(date +%s), "value": 1}], + "tags": ["service:lace-wallet", "env:ci", "workflow:ci", "status:${{ job.status }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}", "job:prepare"] + }, { + "metric": "lace.build.duration", + "points": [{"timestamp": $(date +%s), "value": ${{ github.run_duration }}}], + "tags": ["service:lace-wallet", "env:ci", "workflow:ci", "job:prepare", "repo:${{ github.repository }}"] + }] + }') + echo "Datadog API response: $response" + else + echo "No DATADOG_API_KEY provided, skipping build metrics" + fi + unitTests: - name: Unit tests + name: Unit Tests runs-on: ubuntu-22.04 needs: prepare @@ -140,13 +184,35 @@ jobs: name: packages-bitcoin path: packages/bitcoin/dist - - name: Collect Workflow Telemetry Unit Tests - uses: catchpoint/workflow-telemetry-action@v2 - with: - comment_on_pr: false + - name: Run unit tests + run: yarn test + env: + AVAILABLE_CHAINS: 'Preprod,Preview,Mainnet' + DEFAULT_CHAIN: 'Preprod' + NODE_OPTIONS: '--max_old_space_size=8192' - - name: Execute unit tests - uses: ./.github/actions/test/unit + - name: Send test metrics to Datadog + run: | + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "Sending test metrics to Datadog v2..." + response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d '{ + "series": [{ + "metric": "lace.tests.unit", + "points": [{"timestamp": $(date +%s), "value": 1}], + "tags": ["service:lace-wallet", "env:ci", "workflow:unitTests", "status:${{ job.status }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}", "test_type:unit"] + }, { + "metric": "lace.tests.duration", + "points": [{"timestamp": $(date +%s), "value": ${{ github.run_duration }}}], + "tags": ["service:lace-wallet", "env:ci", "workflow:unitTests", "test_type:unit", "repo:${{ github.repository }}"] + }] + }') + echo "Datadog API response: $response" + else + echo "No DATADOG_API_KEY provided, skipping test metrics" + fi release-pkg: name: Release package @@ -231,322 +297,77 @@ jobs: SENTRY_ENVIRONMENT: 'production' DAPP_RADAR_API_KEY: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.DAPP_RADAR_API_KEY || '' }} - - name: Build Lace Firefox addon - uses: ./.github/actions/build/app - with: - BROWSER_TARGET: 'firefox' - BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }} - BLOCKFROST_PROJECT_ID_PREPROD: ${{ secrets.BLOCKFROST_PROJECT_ID_PREPROD }} - BLOCKFROST_PROJECT_ID_PREVIEW: ${{ secrets.BLOCKFROST_PROJECT_ID_PREVIEW }} - MAESTRO_PROJECT_ID_MAINNET: ${{ secrets.MAESTRO_PROJECT_ID_MAINNET }} - MAESTRO_PROJECT_ID_TESTNET: ${{ secrets.MAESTRO_PROJECT_ID_TESTNET }} - DIR: apps/browser-extension-wallet - NAME: lace-firefox-addon - LACE_EXTENSION_KEY: ${{ secrets.MANIFEST_PUBLIC_KEY }} - POSTHOG_PRODUCTION_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.POSTHOG_PRODUCTION_TOKEN || '' }} - PRODUCTION_MODE_TRACKING: ${{ startsWith(github.ref, 'refs/heads/release') && 'true' || 'false' }} - BANXA_LACE_URL: ${{ startsWith(github.ref, 'refs/heads/release') && 'https://lacewallet.banxa.com/' }} - SENTRY_AUTH_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.SENTRY_AUTH_TOKEN || '' }} - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - SENTRY_ORG: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_ORG || '' }} - SENTRY_PROJECT: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_PROJECT || ''}} - SENTRY_ENVIRONMENT: 'production' - DAPP_RADAR_API_KEY: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.DAPP_RADAR_API_KEY || '' }} - - build: - name: Build Lace - runs-on: ubuntu-22.04 - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Build Lace artifact - uses: ./.github/shared/build - with: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - LACE_EXTENSION_KEY: ${{ secrets.MANIFEST_PUBLIC_KEY }} - BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }} - BLOCKFROST_PROJECT_ID_PREPROD: ${{ secrets.BLOCKFROST_PROJECT_ID_PREPROD }} - BLOCKFROST_PROJECT_ID_PREVIEW: ${{ secrets.BLOCKFROST_PROJECT_ID_PREVIEW }} - BLOCKFROST_PROJECT_ID_SANCHONET: ${{ secrets.BLOCKFROST_PROJECT_ID_SANCHONET }} - MAESTRO_PROJECT_ID_MAINNET: ${{ secrets.MAESTRO_PROJECT_ID_MAINNET }} - MAESTRO_PROJECT_ID_TESTNET: ${{ secrets.MAESTRO_PROJECT_ID_TESTNET }} - SENTRY_AUTH_TOKEN: ${{ startsWith(github.ref, 'refs/heads/release') && secrets.SENTRY_AUTH_TOKEN || '' }} - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} - SENTRY_ORG: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_ORG || '' }} - SENTRY_PROJECT: ${{ startsWith(github.ref, 'refs/heads/release') && vars.SENTRY_PROJECT || ''}} - SENTRY_ENVIRONMENT: 'smoke-tests' - WALLET_POLLING_INTERVAL_IN_SEC: 5 - - - name: Upload build artifact - uses: actions/upload-artifact@v4 - with: - name: '${{ env.BUILD_ARTIFACT_NAME }}' - path: ./apps/browser-extension-wallet/dist - - smokeTests: - name: Smoke e2e tests - runs-on: ubuntu-22.04 - needs: build - strategy: - fail-fast: false - matrix: - batch: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Node.js and install dependencies - uses: ./.github/actions/install - with: - WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - - name: Download Lace build artifact - uses: actions/download-artifact@v4 - with: - name: '${{ env.BUILD_ARTIFACT_NAME }}' - path: ./apps/browser-extension-wallet/dist - - - name: Execute E2E tests - uses: ./.github/actions/test/e2e - with: - BATCH: ${{ matrix.batch }} - SMOKE_ONLY: true - TEST_DAPP_URL: ${{ secrets.TEST_DAPP_URL }} - WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} - SERVICE_WORKER_LOGS: true - - processReports: - name: Process smoke e2e test reports - runs-on: ubuntu-22.04 - needs: smokeTests - if: always() - steps: - - name: Download all smoke tests artifacts - uses: actions/download-artifact@v4 - with: - path: . - pattern: 'runner-artifacts-*' - merge-multiple: true - - - name: Create allure properties - shell: bash - if: always() - working-directory: ./reports/allure/results + - name: Send release metrics to Datadog run: | - echo " - branch=${{ github.ref_name }} - browser= 'Chrome' - tags= '@Smoke' - platform=Linux - " > environment.properties - - - name: Publish allure report to S3 - uses: andrcuns/allure-publish-action@v2.9.0 - if: always() - env: - GITHUB_AUTH_TOKEN: ${{ secrets.GH_TOKEN }} - AWS_ACCESS_KEY_ID: ${{ secrets.E2E_AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.E2E_AWS_SECRET_ACCESS_KEY }} - with: - storageType: s3 - resultsGlob: './reports/allure/results' - bucket: lace-e2e-test-results - prefix: 'smoke/linux/chrome/${{ github.run_number }}' - copyLatest: true - ignoreMissingResults: true - updatePr: comment - baseUrl: 'https://${{ secrets.E2E_REPORTS_USER }}:${{ secrets.E2E_REPORTS_PASSWORD }}@${{ secrets.E2E_REPORTS_URL }}' - - - name: Publish artifacts (logs, reports, screenshots) - uses: actions/upload-artifact@v4 - if: always() - with: - name: test-artifacts - path: | - ./packages/e2e-tests/screenshots - ./packages/e2e-tests/logs - ./packages/e2e-tests/reports - retention-days: 5 - - - run: | - if [[ ${{ needs.smokeTests.result }} == "success" ]]; then - exit 0 + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "Sending release metrics to Datadog v2..." + response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d '{ + "series": [{ + "metric": "lace.release.package", + "points": [{"timestamp": $(date +%s), "value": 1}], + "tags": ["service:lace-wallet", "env:ci", "workflow:release-pkg", "status:${{ job.status }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}", "artifact:lace-browser-extension"] + }, { + "metric": "lace.release.duration", + "points": [{"timestamp": $(date +%s), "value": ${{ github.run_duration }}}], + "tags": ["service:lace-wallet", "env:ci", "workflow:release-pkg", "repo:${{ github.repository }}"] + }] + }') + echo "Datadog API response: $response" else - exit 1 + echo "No DATADOG_API_KEY provided, skipping release metrics" fi - if-core-changed: - name: When core changed - if: ${{ github.event.pull_request.draft == false }} - runs-on: ubuntu-22.04 - outputs: - requireChromaticCheck: ${{ steps.diffcheck.outputs.requireChromaticCheck }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - id: diffcheck - run: | - set +e - git diff --quiet ${{ github.event.pull_request.base.sha }}..${{ github.sha }} -- packages/core/** - echo "requireChromaticCheck=$?" >> "$GITHUB_OUTPUT" - cat $GITHUB_OUTPUT - set -e - - chromaticCore: - name: > - Run Chromatic check: Core - runs-on: ubuntu-22.04 - needs: - - prepare - - if-core-changed - - steps: - - name: Checkout repository - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js and install dependencies - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: ./.github/actions/install - with: - WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - - name: Download packages-common - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-common - path: packages/common/dist - - - name: Download packages-cardano - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-cardano - path: packages/cardano/dist - - - name: Download packages-translation - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-translation - path: packages/translation/dist - - - name: Download packages-core - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-core - path: packages/core/dist - - - name: Chromatic packages-core - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 1 }} - uses: ./.github/actions/chromatic - with: - DIR: packages/core - NAME: packages-core - TOKEN: ${{ secrets.CHROMATIC_LACE_CORE_TOKEN }} - - - name: Skip - if: ${{ needs.if-core-changed.outputs.requireChromaticCheck == 0 }} - run: echo "Chromatic check for packages/core not needed" - exit 0 - - if-staking-changed: - name: When staking change - if: ${{ github.event.pull_request.draft == false }} - runs-on: ubuntu-22.04 - outputs: - requireChromaticCheck: ${{ steps.diffcheck.outputs.requireChromaticCheck }} + datadog-final: + needs: [prepare, unitTests, release-pkg] + runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - id: diffcheck + - name: Send final CI metrics to Datadog run: | - set +e - git diff --quiet ${{ github.event.pull_request.base.sha }}..${{ github.sha }} -- packages/staking/** - echo "requireChromaticCheck=$?" >> "$GITHUB_OUTPUT" - cat $GITHUB_OUTPUT - set -e - - chromaticStaking: - name: > - Run Chromatic check: Staking - runs-on: ubuntu-22.04 - needs: - - prepare - - if-staking-changed - - steps: - - name: Checkout repository - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js and install dependencies - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: ./.github/actions/install - with: - WALLET_PASSWORD: ${{ secrets.WALLET_PASSWORD_TESTNET }} - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - - name: Download packages-common - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-common - path: packages/common/dist - - - name: Download packages-cardano - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-cardano - path: packages/cardano/dist - - - name: Download packages-translation - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-translation - path: packages/translation/dist - - - name: Download packages-core - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-core - path: packages/core/dist - - - name: Download packages-staking - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: actions/download-artifact@v4 - with: - name: packages-staking - path: packages/staking/dist - - - name: Chromatic packages-staking - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 1 }} - uses: ./.github/actions/chromatic - with: - DIR: packages/staking - NAME: packages-staking - TOKEN: ${{ secrets.CHROMATIC_LACE_STAKING_TOKEN }} - - - name: Skip - if: ${{ needs.if-staking-changed.outputs.requireChromaticCheck == 0 }} - run: echo "Chromatic check for packages/staking not needed" - exit 0 + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "Sending final metrics to Datadog v2..." + + # Calculate overall pipeline status + if [ "${{ needs.prepare.result }}" = "success" ] && [ "${{ needs.unitTests.result }}" = "success" ] && [ "${{ needs.release-pkg.result }}" = "success" ]; then + overall_status="success" + else + overall_status="failure" + fi + + # Get current timestamp + timestamp=$(date +%s) + + # Send final metrics + response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "{ + \"series\": [{ + \"metric\": \"github.ci.pipeline.final_status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:ci\", \"workflow:ci\", \"status:$overall_status\", \"repo:${{ github.repository }}\", \"branch:${{ github.ref_name }}\", \"commit:${{ github.sha }}\"] + }, { + \"metric\": \"github.ci.pipeline.total_duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": ${{ github.run_duration }}}], + \"tags\": [\"service:lace-wallet\", \"env:ci\", \"workflow:ci\", \"repo:${{ github.repository }}\", \"branch:${{ github.ref_name }}\"] + }] + }") + echo "Datadog API response: $response" + + # Send event using v1 API (more reliable for events) + event_response=$(curl -s -w "%{http_code}" -X POST "https://api.us5.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "{ + \"title\": \"Lace CI Pipeline Complete\", + \"text\": \"All CI jobs completed for ${{ github.repository }}\nBranch: ${{ github.ref_name }}\nCommit: ${{ github.sha }}\nStatus: ${{ needs.prepare.result }}, ${{ needs.unitTests.result }}, ${{ needs.release-pkg.result }}\nOverall: $overall_status\", + \"tags\": [\"service:lace-wallet\", \"env:ci\", \"workflow:ci\", \"repo:lace\", \"status:$overall_status\"], + \"alert_type\": \"$overall_status\", + \"source_type_name\": \"github\" + }") + echo "Datadog Event API response: $event_response" + else + echo "No DATADOG_API_KEY provided, skipping final metrics" + fi \ No newline at end of file diff --git a/.github/workflows/datadog-ci.yml b/.github/workflows/datadog-ci.yml new file mode 100644 index 0000000000..b58d1d06b6 --- /dev/null +++ b/.github/workflows/datadog-ci.yml @@ -0,0 +1,89 @@ +name: Datadog CI Integration + +on: + workflow_call: + inputs: + datadog-api-key: + required: true + type: string + description: 'Datadog API key for CI metrics and logs' + datadog-site: + required: false + type: string + default: 'datadoghq.com' + description: 'Datadog site (datadoghq.com, datadoghq.eu, etc.)' + service-name: + required: true + type: string + description: 'Service name for Datadog metrics' + environment: + required: false + type: string + default: 'ci' + description: 'Environment name' + tags: + required: false + type: string + default: 'ci:true' + description: 'Additional tags for metrics (comma-separated)' + +jobs: + datadog-setup: + runs-on: ubuntu-latest + outputs: + dd-trace-id: ${{ steps.datadog-setup.outputs.trace-id }} + dd-span-id: ${{ steps.datadog-setup.outputs.span-id }} + steps: + - name: Setup Datadog CI + id: datadog-setup + run: | + echo "trace-id=$(date +%s)" >> $GITHUB_OUTPUT + echo "span-id=$(date +%s)" >> $GITHUB_OUTPUT + + datadog-monitor: + runs-on: ubuntu-latest + needs: datadog-setup + if: always() + steps: + - name: Send CI metrics to Datadog + run: | + curl -X POST "https://api.${{ inputs.datadog-site }}/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ inputs.datadog-api-key }}" \ + -d '{ + "series": [{ + "metric": "github.ci.pipeline.duration", + "points": [[$(date +%s), ${{ github.run_duration }}]], + "tags": ["service:${{ inputs.service-name }}", "env:${{ inputs.environment }}", "workflow:${{ github.workflow }}", "job:${{ github.job }}"], + "type": "gauge" + }, { + "metric": "github.ci.pipeline.status", + "points": [[$(date +%s), 1]], + "tags": ["service:${{ inputs.service-name }}", "env:${{ inputs.environment }}", "workflow:${{ github.workflow }}", "job:${{ github.job }}", "status:${{ job.status }}"], + "type": "gauge" + }, { + "metric": "github.ci.repository.workflow_runs", + "points": [[$(date +%s), 1]], + "tags": ["service:${{ inputs.service-name }}", "env:${{ inputs.environment }}", "repo:${{ github.repository }}", "branch:${{ github.ref_name }}"], + "type": "gauge" + }, { + "metric": "github.ci.job.duration", + "points": [[$(date +%s), ${{ github.run_duration }}]], + "tags": ["service:${{ inputs.service-name }}", "env:${{ inputs.environment }}", "job:${{ github.job }}", "runner:${{ runner.os }}"], + "type": "gauge" + }] + }' + + - name: Send CI events to Datadog + if: always() + run: | + curl -X POST "https://api.${{ inputs.datadog-site }}/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ inputs.datadog-api-key }}" \ + -d '{ + "title": "Lace CI Pipeline: ${{ github.workflow }}", + "text": "Workflow ${{ github.workflow }} completed with status: ${{ job.status }}\nRepository: ${{ github.repository }}\nBranch: ${{ github.ref_name }}\nCommit: ${{ github.sha }}", + "tags": ["service:${{ inputs.service-name }}", "env:${{ inputs.environment }}", "workflow:${{ github.workflow }}", "status:${{ job.status }}", "repo:${{ github.repository }}"], + "alert_type": "${{ job.status == 'success' && 'info' || 'error' }}", + "source_type_name": "github" + }' \ No newline at end of file diff --git a/.github/workflows/e2e-tests-linux-split.yml b/.github/workflows/e2e-tests-linux-split.yml index e1b6a89d96..d1dcde4284 100644 --- a/.github/workflows/e2e-tests-linux-split.yml +++ b/.github/workflows/e2e-tests-linux-split.yml @@ -193,6 +193,9 @@ jobs: # when cancelling job always() will prevent step from being cancelled and we don't want process results in this case if: ${{ success() || failure() }} steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Download all artifacts uses: actions/download-artifact@v4 with: @@ -212,6 +215,11 @@ jobs: tags=${{ needs.setup.outputs.tags }} " > environment.properties + - name: Convert metrics JSON to Datadog format + working-directory: './packages/e2e-tests/tools/' + run: | + bash convert_metrics_to_datadog.sh "${{ github.workflow }}" "${{ github.run_id }}" ../../../artifacts/metrics "${{ secrets.DATADOG_API_KEY }}" + - name: Publish allure report to S3 uses: andrcuns/allure-publish-action@v2.9.0 env: @@ -260,3 +268,77 @@ jobs: with: name: performance-metrics path: ./artifacts/metrics + + - name: Send E2E metrics to Datadog + run: | + echo "📊 E2E metrics have been sent to Datadog via the conversion script" + echo "📁 Datadog payload saved to: ./artifacts/metrics/datadog_payload.json" + echo "🔍 Check the previous step for detailed metrics information" + + # ------------------------------------------------------------------------ + # 3) Write Alloy (River) config — scrape localhost:9101 and remote_write + # ------------------------------------------------------------------------ + + + # ------------------------------------------------------------------------ + # 4) Launch Alloy for ~45 s to scrape + push the data, then shut it down. + # ------------------------------------------------------------------------ + + + # - name: Create Prometheus config + # env: + # PUSH_URL: ${{ secrets.GRAFANA_PUSH_URL }} # e.g., https://prometheus-us-central1.grafana.net/api/prom/push + # PUSH_USER: ${{ secrets.GRAFANA_USERNAME }} # e.g., 787878 + # PUSH_PASS: ${{ secrets.GRAFANA_PASSWORD }} # e.g., eyJrIjoxxxxxxxxxxxxxxyMX0= + # run: | + # cat >prometheus.yml < http.log 2>&1 + # printf '\n*****************\n' + # echo 'This is my current directory:' + # pwd + # printf '\n*****************\n' + # echo 'This is ls -al in that directory' + # ls -al + # printf '\n*****************\n' + # + # - name: Run Prometheus + # run: | + # # Enable logs for debugging + # #docker run --name prometheus -v $(pwd):/etc/prometheus -p 9090:9090 --link pushgateway:pushgateway prom/prometheus:latest --config.file=/etc/prometheus/prometheus.yml --web.listen-address=:9090 --log.level=debug + # docker run -d --name prometheus -v $(pwd):/etc/prometheus -p 9090:9090 --link pushgateway:pushgateway prom/prometheus:latest --config.file=/etc/prometheus/prometheus.yml --web.listen-address=:9090 > prom.log 2>&1 + # sleep 60 + # # Uncomment for troubleshooting. + # printf '\n*****************\n' + # printf '\n curl e2e_cpu_seconds_total \n' + # curl http://localhost:9090/api/v1/query?query=e2e_cpu_seconds_total_v1 + # printf '\n*****************\n' + # printf '\n cat prom.log \n' + # cat prom.log + # #printf '\n*****************\n' + # #printf '\n send_failures_total \n' + # #curl 'http://localhost:9090/api/v1/query?query=prometheus_remote_storage_queue_send_failures_total' + # #printf '\n*****************\n' + # #printf '\n storage_retries_total \n' + # #curl 'http://localhost:9090/api/v1/query?query=prometheus_remote_storage_retries_total' + + diff --git a/.github/workflows/test-datadog.yml b/.github/workflows/test-datadog.yml new file mode 100644 index 0000000000..e4da957185 --- /dev/null +++ b/.github/workflows/test-datadog.yml @@ -0,0 +1,345 @@ +name: Test Datadog v2 API + +on: + workflow_dispatch: + push: + branches: [ main, test/berno_prom_metrics ] + +jobs: + test-datadog: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Test Datadog v2 API + run: | + echo "🔍 Starting Datadog v2 API test..." + echo "📊 API Key present: $([ -n "${{ secrets.DATADOG_API_KEY }}" ] && echo "YES" || echo "NO")" + echo "🌐 Datadog Site: us5.datadoghq.com" + echo "⏰ Timestamp: $(date)" + echo "📝 Workflow: ${{ github.workflow }}" + echo "🏷️ Repository: ${{ github.repository }}" + echo "🌿 Branch: ${{ github.ref_name }}" + echo "🔗 Commit: ${{ github.sha }}" + echo "" + + if [ -n "${{ secrets.DATADOG_API_KEY }}" ]; then + echo "✅ API Key is set, proceeding with test..." + + # Prepare the JSON payload (v2 API format) - Comprehensive CI metrics + timestamp=$(date +%s) + json_payload="{ + \"series\": [ + { + \"metric\": \"test.datadog.integration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 42}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\"] + }, + { + \"metric\": \"test.datadog.simple\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 100}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\"] + }, + { + \"metric\": \"github.ci.pipeline.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 120}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test-datadog\"] + }, + { + \"metric\": \"github.ci.pipeline.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"status:success\"] + }, + { + \"metric\": \"github.ci.repository.workflow_runs\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"repo:${{ github.repository }}\", \"branch:${{ github.ref_name }}\"] + }, + { + \"metric\": \"github.ci.job.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 120}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test-datadog\", \"runner:${{ runner.os }}\"] + }, + { + \"metric\": \"lace.ci.build.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 180}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:build\", \"type:typescript\"] + }, + { + \"metric\": \"lace.ci.build.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:build\", \"status:success\"] + }, + { + \"metric\": \"lace.ci.e2e.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 420}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:e2e\", \"type:playwright\"] + }, + { + \"metric\": \"lace.ci.e2e.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:e2e\", \"status:success\"] + }, + { + \"metric\": \"lace.ci.artifact.size\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 52428800}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:artifact\", \"type:extension\"] + }, + { + \"metric\": \"lace.ci.artifact.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:artifact\", \"status:success\"] + }, + { + \"metric\": \"lace.ci.test.unit.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 45}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test\", \"type:unit\"] + }, + { + \"metric\": \"lace.ci.test.unit.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test\", \"type:unit\", \"status:success\"] + }, + { + \"metric\": \"lace.ci.test.integration.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 180}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test\", \"type:integration\"] + }, + { + \"metric\": \"lace.ci.test.integration.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:test\", \"type:integration\", \"status:success\"] + }, + { + \"metric\": \"lace.ci.lint.duration\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 15}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:lint\", \"type:eslint\"] + }, + { + \"metric\": \"lace.ci.lint.status\", + \"points\": [{\"timestamp\": $timestamp, \"value\": 1}], + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"job:lint\", \"type:eslint\", \"status:success\"] + } + ] + }" + + echo "📤 Sending JSON payload:" + echo "$json_payload" + echo "" + echo "🔍 JSON validation:" + echo "$json_payload" | jq '.' 2>/dev/null && echo "✅ JSON is valid" || echo "❌ JSON is invalid" + echo "" + + # Send metrics to Datadog v2 API + echo "🚀 Sending request to Datadog v2 API..." + response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\nTOTAL_TIME:%{time_total}s\n" \ + -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "$json_payload") + + echo "📥 Raw response:" + echo "$response" + echo "" + + # Extract HTTP status code + http_code=$(echo "$response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + total_time=$(echo "$response" | grep "TOTAL_TIME:" | cut -d: -f2) + response_body=$(echo "$response" | sed '/HTTP_STATUS_CODE:/d' | sed '/TOTAL_TIME:/d') + + echo "📊 Response Analysis:" + echo " HTTP Status Code: $http_code" + echo " Response Time: ${total_time}s" + echo " Response Body: $response_body" + echo "" + + if [ "$http_code" = "202" ]; then + echo "✅ SUCCESS: Metrics sent successfully to Datadog!" + echo " Status: $http_code" + echo " Time: ${total_time}s" + else + echo "❌ ERROR: Failed to send metrics to Datadog" + echo " Status: $http_code" + echo " Error: $response_body" + echo "" + echo "🔍 Troubleshooting tips:" + echo " 1. Check API key permissions in Datadog" + echo " 2. Verify the API key is correct" + echo " 3. Check if the key has 'Metrics Write' permission" + echo " 4. Ensure you're looking at us5.datadoghq.com" + fi + + # Test CI Events functionality + echo "" + echo "📝 Testing CI Events..." + echo "🔍 Debug Info:" + echo " Datadog Site: us5.datadoghq.com" + echo " Events API: https://api.us5.datadoghq.com/api/v1/events" + echo " API Key: $([ -n "${{ secrets.DATADOG_API_KEY }}" ] && echo "SET" || echo "NOT SET")" + echo "" + + event_payload="{ + \"title\": \"Test Datadog CI Event: ${{ github.workflow }}\", + \"text\": \"Test workflow ${{ github.workflow }} completed successfully\\nRepository: ${{ github.repository }}\\nBranch: ${{ github.ref_name }}\\nCommit: ${{ github.sha }}\", + \"tags\": [\"service:lace-wallet\", \"env:test\", \"workflow:test-datadog\", \"status:success\", \"repo:${{ github.repository }}\"], + \"alert_type\": \"info\", + \"source_type_name\": \"github\" + }" + + echo "📤 Sending CI event payload:" + echo "$event_payload" + echo "" + echo "🔍 JSON validation for event:" + echo "$event_payload" | jq '.' 2>/dev/null && echo "✅ Event JSON is valid" || echo "❌ Event JSON is invalid" + echo "" + + event_response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\nTOTAL_TIME:%{time_total}s\n" \ + -X POST "https://api.us5.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "$event_payload") + + echo "📥 Raw event response:" + echo "$event_response" + echo "" + + event_http_code=$(echo "$event_response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + event_total_time=$(echo "$event_response" | grep "TOTAL_TIME:" | cut -d: -f2) + event_response_body=$(echo "$event_response" | sed '/HTTP_STATUS_CODE:/d' | sed '/TOTAL_TIME:/d') + + echo "📊 Event Response Analysis:" + echo " HTTP Status Code: $event_http_code" + echo " Response Time: ${event_total_time}s" + echo " Response Body: $event_response_body" + echo "" + + if [ "$event_http_code" = "202" ]; then + echo "✅ SUCCESS: CI Event sent successfully to Datadog!" + echo " Status: $event_http_code" + echo " Time: ${event_total_time}s" + else + echo "❌ ERROR: Failed to send CI Event to Datadog" + echo " Status: $event_http_code" + echo " Error: $event_response_body" + echo "" + echo "🔍 Event troubleshooting tips:" + echo " 1. Check if API key has 'Events Write' permission" + echo " 2. Verify the event payload format" + echo " 3. Check Datadog v1 events API documentation" + echo " 4. Ensure you're using the correct endpoint" + fi + + # Test API permissions and try different event formats + echo "" + echo "🔍 Testing API permissions and alternative formats..." + + # Test 1: Check if we can read events (permissions test) + echo "📋 Test 1: Checking API permissions..." + permissions_response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\n" \ + -X GET "https://api.us5.datadoghq.com/api/v1/events?start=$(date -d '1 hour ago' +%s)&end=$(date +%s)" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -H "Content-Type: application/json") + + permissions_http_code=$(echo "$permissions_response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + echo " Events Read Permission: $permissions_http_code" + + # Test 2: Try minimal event format + echo "" + echo "📋 Test 2: Minimal event format..." + minimal_event_payload="{ + \"title\": \"Minimal Test\", + \"text\": \"Minimal test event\", + \"tags\": [\"test:minimal\"] + }" + + minimal_response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\nTOTAL_TIME:%{time_total}s\n" \ + -X POST "https://api.us5.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "$minimal_event_payload") + + minimal_http_code=$(echo "$minimal_response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + minimal_response_body=$(echo "$minimal_response" | sed '/HTTP_STATUS_CODE:/d' | sed '/TOTAL_TIME:/d') + + echo " Minimal Event Status: $minimal_http_code" + echo " Minimal Event Response: $minimal_response_body" + + # Test 3: Create a very distinctive event for easy finding + echo "" + echo "📋 Test 3: Creating distinctive event for UI testing..." + distinctive_event_payload="{ + \"title\": \"🎯 BERNO TEST EVENT - LOOK FOR THIS ONE\", + \"text\": \"This is a distinctive test event created at $(date). Look for this exact title in the Events Explorer.\\n\\nRepository: ${{ github.repository }}\\nWorkflow: ${{ github.workflow }}\\nTimestamp: $(date +%s)\", + \"tags\": [\"test:distinctive\", \"user:berno\", \"search:me\", \"service:lace-wallet\"], + \"alert_type\": \"info\", + \"priority\": \"normal\" + }" + + distinctive_response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\nTOTAL_TIME:%{time_total}s\n" \ + -X POST "https://api.us5.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: ${{ secrets.DATADOG_API_KEY }}" \ + -d "$distinctive_event_payload") + + distinctive_http_code=$(echo "$distinctive_response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + distinctive_response_body=$(echo "$distinctive_response" | sed '/HTTP_STATUS_CODE:/d' | sed '/TOTAL_TIME:/d') + + echo " Distinctive Event Status: $distinctive_http_code" + echo " Distinctive Event Response: $distinctive_response_body" + + # Extract the event ID for direct URL + if [ "$distinctive_http_code" = "202" ]; then + event_id=$(echo "$distinctive_response_body" | jq -r '.event.id_str' 2>/dev/null) + if [ -n "$event_id" ] && [ "$event_id" != "null" ]; then + echo " 🎯 Direct URL: https://us5.datadoghq.com/event/event?id=$event_id" + echo " 🔍 Search for: 'BERNO TEST EVENT' in Events Explorer" + fi + fi + + # Summary + echo "" + echo "📊 API Test Summary:" + echo " Original Event: $event_http_code" + echo " Read Permission: $permissions_http_code" + echo " Minimal Event: $minimal_http_code" + echo " Distinctive Event: $distinctive_http_code" + echo "" + echo "🔍 Troubleshooting Guide:" + echo " - 202: Success (events created successfully)" + echo " - 403: Forbidden (API key lacks permissions)" + echo " - 401: Unauthorized (invalid API key)" + echo " - 400: Bad Request (payload format issue)" + echo "" + echo "🎯 To find events in Datadog UI:" + echo " 1. Go to: https://us5.datadoghq.com/event/explorer" + echo " 2. Search for: 'BERNO TEST EVENT' or 'Test Datadog CI Event'" + echo " 3. Check time range: Last 1 hour" + echo " 4. Clear any filters on the left sidebar" + echo " 5. Try direct URLs from the logs above" + + echo "" + echo "🔍 To verify in Datadog UI:" + echo " 1. Go to Metrics Explorer" + echo " 2. Search for: test.datadog.integration" + echo " 3. Set time range to 'Last 1 hour'" + echo " 4. Look for metrics with tags: service:lace-wallet, env:test" + echo "" + echo "📊 Also check for CI metrics:" + echo " 5. Search for: github.ci.pipeline.duration" + echo " 6. Search for: github.ci.pipeline.status" + echo " 7. Check Events tab for CI events" + echo " 8. Look for event titled: 'Test Datadog CI Event: test-datadog'" + + else + echo "❌ ERROR: DATADOG_API_KEY secret is not set" + echo "" + echo "🔧 To fix this:" + echo " 1. Go to repository Settings → Secrets and variables → Actions" + echo " 2. Add a new repository secret named 'DATADOG_API_KEY'" + echo " 3. Set the value to your Datadog API key" + echo " 4. Make sure the key has 'Metrics Write' permission" + fi + + echo "" + echo "🏁 Test completed at $(date)" \ No newline at end of file diff --git a/datadog-metrics-guide.md b/datadog-metrics-guide.md new file mode 100644 index 0000000000..1f9f740d36 --- /dev/null +++ b/datadog-metrics-guide.md @@ -0,0 +1,114 @@ +# Datadog Metrics Guide for Lace CI + +## ✅ **Good News: Your Datadog Integration is Working!** + +Your API key is valid and the workflow is successfully sending both **metrics** and **events** to Datadog. + +## 📊 **Metrics Being Sent** + +The workflow sends these metrics to Datadog: + +### 1. **CI Pipeline Metrics** +- **Metric Name**: `github.ci.pipeline.duration` +- **Tags**: `service:lace-wallet`, `env:ci`, `workflow:ci`, `job:datadog-ci` +- **Type**: Gauge +- **Description**: Duration of CI pipeline execution + +- **Metric Name**: `github.ci.pipeline.status` +- **Tags**: `service:lace-wallet`, `env:ci`, `workflow:ci`, `job:datadog-ci`, `status:success/failure` +- **Type**: Gauge +- **Description**: Success/failure status of CI pipeline + +### 2. **Build Metrics** +- **Metric Name**: `lace.build.packages` +- **Tags**: `service:lace-wallet`, `env:ci`, `workflow:ci`, `status:success/failure` +- **Type**: Gauge +- **Description**: Build package completion status + +### 3. **Test Metrics** +- **Metric Name**: `lace.tests.unit` +- **Tags**: `service:lace-wallet`, `env:ci`, `workflow:ci`, `status:success/failure` +- **Type**: Gauge +- **Description**: Unit test execution status + +### 4. **Release Metrics** +- **Metric Name**: `lace.release.package` +- **Tags**: `service:lace-wallet`, `env:ci`, `workflow:release-pkg`, `status:success/failure` +- **Type**: Gauge +- **Description**: Release package creation status + +## 🔍 **How to Find These Metrics in Datadog** + +### **Method 1: Metrics Explorer** +1. Go to **Metrics** → **Explorer** in Datadog +2. Search for these metric names: + - `github.ci.pipeline.duration` + - `github.ci.pipeline.status` + - `lace.build.packages` + - `lace.tests.unit` + - `lace.release.package` + +### **Method 2: Query by Service** +1. Go to **Metrics** → **Explorer** +2. Filter by: `service:lace-wallet` +3. This will show all metrics tagged with your service + +### **Method 3: Query by Environment** +1. Go to **Metrics** → **Explorer** +2. Filter by: `env:ci` +3. This will show all CI-related metrics + +### **Method 4: Events Section** +1. Go to **Events** in Datadog +2. Look for events with title: "Lace CI Pipeline Complete" +3. Filter by: `service:lace-wallet` + +## 📈 **Sample Queries for Dashboards** + +### **Pipeline Success Rate** +``` +sum:github.ci.pipeline.status{status:success,service:lace-wallet} / sum:github.ci.pipeline.status{service:lace-wallet} +``` + +### **Average Pipeline Duration** +``` +avg:github.ci.pipeline.duration{service:lace-wallet} +``` + +### **Build Success Rate** +``` +sum:lace.build.packages{status:success,service:lace-wallet} / sum:lace.build.packages{service:lace-wallet} +``` + +### **Test Success Rate** +``` +sum:lace.tests.unit{status:success,service:lace-wallet} / sum:lace.tests.unit{service:lace-wallet} +``` + +## 🚨 **Troubleshooting** + +### **If you can't see metrics:** +1. **Wait 5-10 minutes** - Metrics can take time to appear +2. **Check the time range** - Make sure you're looking at recent data +3. **Verify tags** - Use the exact tag combinations listed above +4. **Check for typos** - Metric names are case-sensitive + +### **If you see events but not metrics:** +1. **Check the workflow logs** - Look for "Sending metrics to Datadog..." messages +2. **Verify API responses** - Should show HTTP 202 for success +3. **Check metric names** - Use the exact names listed above + +## 🎯 **Next Steps** + +1. **Create a dashboard** using the sample queries above +2. **Set up alerts** for pipeline failures +3. **Monitor trends** in build and test performance +4. **Share the dashboard** with your team + +## 📞 **Support** + +If you still can't see the metrics: +1. Check the workflow logs for any error messages +2. Verify the metric names in the Datadog Metrics Explorer +3. Try the sample queries above +4. Contact Datadog support if needed \ No newline at end of file diff --git a/debug-datadog-setup.md b/debug-datadog-setup.md new file mode 100644 index 0000000000..1d998092c6 --- /dev/null +++ b/debug-datadog-setup.md @@ -0,0 +1,80 @@ +# Debugging Datadog CI Metrics Issue + +## Current Status Check + +### 1. Verify Workflow Files +- ✅ `ci-with-datadog.yml` exists and has datadog integration +- ✅ `datadog-ci.yml` exists as reusable workflow +- ❓ **Main issue**: Regular `ci.yml` might still be running instead + +### 2. Check GitHub Secrets +Go to: `https://github.com/input-output-hk/lace/settings/secrets/actions` + +Verify these secrets exist: +- `DATADOG_API_KEY` - Your Datadog API key +- Other required secrets for the workflow + +### 3. Test API Key Locally +```bash +# Set your API key (replace with actual key) +export DATADOG_API_KEY=your_api_key_here + +# Run the test script +./test-datadog.sh +``` + +### 4. Check Workflow Triggers +The `ci-with-datadog.yml` should trigger on: +- ✅ `test/**` branches (your current branch: `test/berno_prom_metrics`) +- ✅ Pull requests +- ✅ Manual dispatch + +### 5. Force Workflow to Run +To test if the workflow works: + +1. **Option A**: Rename the workflow file + ```bash + git mv .github/workflows/ci.yml .github/workflows/ci-backup.yml + git mv .github/workflows/ci-with-datadog.yml .github/workflows/ci.yml + ``` + +2. **Option B**: Manual trigger + - Go to GitHub Actions tab + - Select "Continuous Integration with Datadog" + - Click "Run workflow" + +### 6. Check Workflow Logs +Look for these messages in the workflow logs: +- ✅ "Sending metrics to Datadog..." +- ✅ "Datadog API response: 202" +- ❌ "No DATADOG_API_KEY provided, skipping metrics" +- ❌ "Failed to send metric to Datadog" + +## Common Issues & Solutions + +### Issue: "No DATADOG_API_KEY provided" +**Solution**: Add the secret to GitHub repository settings + +### Issue: "Failed to send metric to Datadog" +**Solution**: Check API key validity and Datadog account status + +### Issue: Workflow not running +**Solution**: Ensure branch name matches trigger conditions + +### Issue: Wrong workflow running +**Solution**: Rename files to prioritize datadog workflow + +## Next Steps + +1. **Test your API key** using the test script +2. **Check GitHub secrets** are properly configured +3. **Force the datadog workflow** to run +4. **Monitor the logs** for success/error messages +5. **Check Datadog dashboard** for incoming metrics + +## Expected Success Indicators + +- ✅ Workflow runs and shows "Sending metrics to Datadog..." +- ✅ API response shows HTTP 202 +- ✅ Metrics appear in Datadog dashboard within 5-10 minutes +- ✅ Events appear in Datadog Events section \ No newline at end of file diff --git a/debug-metric-sending.sh b/debug-metric-sending.sh new file mode 100755 index 0000000000..02f1cc2803 --- /dev/null +++ b/debug-metric-sending.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# Comprehensive debugging for Datadog metrics +echo "🔍 Debugging Datadog Metric Sending..." + +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY not set" + exit 1 +fi + +echo "✅ Using API Key: ${DATADOG_API_KEY:0:8}..." + +# Test 1: Simple metric with minimal data +echo "" +echo "📊 Test 1: Simple metric..." +response1=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.simple", + "points": [[$(date +%s), 1]], + "type": "gauge" + }] + }') + +http_code1="${response1: -3}" +response_body1="${response1%???}" + +echo "HTTP Code: $http_code1" +echo "Response: $response_body1" + +# Test 2: Metric with tags +echo "" +echo "📊 Test 2: Metric with tags..." +response2=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.with.tags", + "points": [[$(date +%s), 2]], + "tags": ["test:true"], + "type": "gauge" + }] + }') + +http_code2="${response2: -3}" +response_body2="${response2%???}" + +echo "HTTP Code: $http_code2" +echo "Response: $response_body2" + +# Test 3: Metric with service tag +echo "" +echo "📊 Test 3: Metric with service tag..." +response3=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.service", + "points": [[$(date +%s), 3]], + "tags": ["service:test-service"], + "type": "gauge" + }] + }') + +http_code3="${response3: -3}" +response_body3="${response3%???}" + +echo "HTTP Code: $http_code3" +echo "Response: $response_body3" + +# Test 4: Check API key validity +echo "" +echo "🔑 Test 4: Checking API key validity..." +validate_response=$(curl -s -w "%{http_code}" -X GET "https://api.datadoghq.com/api/v1/validate" \ + -H "DD-API-KEY: $DATADOG_API_KEY") + +validate_http_code="${validate_response: -3}" +validate_response_body="${validate_response%???}" + +echo "HTTP Code: $validate_http_code" +echo "Response: $validate_response_body" + +# Test 5: Check organization info +echo "" +echo "🏢 Test 5: Checking organization info..." +org_response=$(curl -s -w "%{http_code}" -X GET "https://api.datadoghq.com/api/v1/org" \ + -H "DD-API-KEY: $DATADOG_API_KEY") + +org_http_code="${org_response: -3}" +org_response_body="${org_response%???}" + +echo "HTTP Code: $org_http_code" +echo "Response: $org_response_body" + +# Summary +echo "" +echo "📊 SUMMARY:" +echo "Test 1 (Simple): $([ "$http_code1" = "202" ] && echo "✅" || echo "❌")" +echo "Test 2 (Tags): $([ "$http_code2" = "202" ] && echo "✅" || echo "❌")" +echo "Test 3 (Service): $([ "$http_code3" = "202" ] && echo "✅" || echo "❌")" +echo "API Key Valid: $([ "$validate_http_code" = "200" ] && echo "✅" || echo "❌")" +echo "Org Info: $([ "$org_http_code" = "200" ] && echo "✅" || echo "❌")" + +echo "" +echo "🔍 Next Steps:" +echo "1. Check if you see 'test.simple' in Datadog Metrics Explorer" +echo "2. Check if you see 'test.with.tags' in Datadog Metrics Explorer" +echo "3. Check if you see 'test.service' in Datadog Metrics Explorer" +echo "4. Wait 5-10 minutes for metrics to appear" +echo "5. Make sure you're looking at 'Last 1 hour' time range" \ No newline at end of file diff --git a/docs/comprehensive-dashboard-fixed.json b/docs/comprehensive-dashboard-fixed.json new file mode 100644 index 0000000000..b74cf2a929 --- /dev/null +++ b/docs/comprehensive-dashboard-fixed.json @@ -0,0 +1,602 @@ +{ + "title": "Lace Wallet Comprehensive CI Dashboard", + "description": "Complete CI/CD monitoring dashboard for Lace Wallet with build, test, e2e, and artifact metrics", + "widgets": [ + { + "definition": { + "title": "Pipeline Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:github.ci.pipeline.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 0, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Average Pipeline Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:github.ci.pipeline.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 2, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Total Workflow Runs", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "count:github.ci.pipeline.status{service:lace-wallet}", + "aggregator": "sum" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 4, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Average Job Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:github.ci.job.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 6, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Build Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.build.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 8, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Build Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.build.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 0, + "y": 2, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "E2E Test Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.e2e.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 2, + "y": 2, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "E2E Test Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.e2e.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 4, + "y": 2, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Unit Test Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.test.unit.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 6, + "y": 2, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Unit Test Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.test.unit.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 8, + "y": 2, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Integration Test Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.test.integration.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 0, + "y": 4, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Integration Test Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.test.integration.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 2, + "y": 4, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Lint Duration (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.lint.duration{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 0, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 4, + "y": 4, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Lint Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.lint.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 6, + "y": 4, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Artifact Size (MB)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.artifact.size{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1 / 1048576" + } + ] + } + ], + "autoscale": true, + "precision": 1, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 8, + "y": 4, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "Artifact Success Rate", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.ci.artifact.status{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 0, + "y": 6, + "width": 2, + "height": 2 + } + } + ], + "template_variables": [], + "layout_type": "ordered", + "notify_list": [], + "reflow_type": "fixed" +} \ No newline at end of file diff --git a/docs/datadog-setup.md b/docs/datadog-setup.md new file mode 100644 index 0000000000..81e113cc3b --- /dev/null +++ b/docs/datadog-setup.md @@ -0,0 +1,173 @@ +# Datadog CI Setup for Lace Wallet + +This is a simple guide to add Datadog monitoring to your Lace CI/CD pipelines. + +## Quick Setup + +### 1. Get Datadog API Key +1. Create account at [datadoghq.com](https://datadoghq.com) (free tier available) +2. Go to **Organization Settings** → **API Keys** +3. Create new API key named "Lace CI Integration" +4. **Important**: Ensure the key has "Metrics Write" permission + +### 2. Add GitHub Secret +1. Go to your Lace repository on GitHub +2. **Settings** → **Secrets and variables** → **Actions** +3. Add new repository secret: + - **Name**: `DATADOG_API_KEY` + - **Value**: Your Datadog API key + +### 3. Use the New Workflow +Replace your current `ci.yml` with `ci-with-datadog.yml` or add Datadog to existing workflows. + +## API Integration Details + +### Datadog v2 API Format +The working payload format for Datadog v2 API: + +```json +{ + "series": [{ + "metric": "test.datadog.integration", + "points": [{"timestamp": 1703123456, "value": 42}], + "tags": ["service:lace-wallet", "env:test", "workflow:test-datadog"] + }] +} +``` + +### Key Requirements +- **Timestamp**: Must be Unix timestamp (seconds since epoch) +- **Points format**: Array of `{"timestamp": X, "value": Y}` objects +- **Tags**: Array of strings in `key:value` format +- **Headers**: + - `Content-Type: application/json` + - `DD-API-KEY: your-api-key` + +### API Endpoint +``` +POST https://api.us5.datadoghq.com/api/v2/series +``` + +## What You'll Get + +### 📊 **One Dashboard for All Pipelines** +- **CI Pipeline**: Unit tests, builds, releases +- **E2E Tests**: Test execution and results +- **Build Pipeline**: Dev preview builds +- **Chromatic**: UI component testing +- **SonarCloud**: Code quality metrics + +### 📈 **Key Metrics** +- Pipeline success/failure rates +- Job execution times +- Build performance trends +- Test coverage trends + +### 🚨 **Smart Alerts** +- Pipeline failures +- Performance degradation +- Test failures +- Build time increases + +## Dashboard Queries + +### Pipeline Success Rate +``` +sum:github.ci.pipeline.status{status:success,service:lace-wallet} / sum:github.ci.pipeline.status{service:lace-wallet} +``` + +### Average Job Duration +``` +avg:github.ci.job.duration{service:lace-wallet} by {workflow} +``` + +### Build Package Metrics +``` +sum:lace.build.packages{service:lace-wallet} +``` + +### Test Results +``` +sum:lace.tests.unit{service:lace-wallet,status:success} +``` + +## Alerts + +### High Failure Rate +``` +sum:github.ci.pipeline.status{status:failure,service:lace-wallet} / sum:github.ci.pipeline.status{service:lace-wallet} > 0.1 +``` + +### Slow Builds +``` +avg:github.ci.job.duration{service:lace-wallet,workflow:ci} > 1800 +``` + +## Troubleshooting + +### Common Issues + +1. **HTTP 403 Forbidden** + - Check API key permissions (needs "Metrics Write") + - Verify API key is correct + - Ensure you're using the right Datadog site (us5.datadoghq.com) + +2. **HTTP 400 Bad Request** + - Check JSON payload format + - Ensure timestamps are Unix timestamps (seconds, not milliseconds) + - Verify tags are in correct format + +3. **HTTP 401 Unauthorized** + - API key is invalid or expired + - Check if the key has proper permissions + +### Testing Your Integration + +Use the `test-datadog.yml` workflow to verify your setup: + +1. **Manual trigger**: Go to Actions → Test Datadog v2 API → Run workflow +2. **Check logs**: Look for "✅ SUCCESS: Metrics sent successfully to Datadog!" +3. **Verify in Datadog**: + - Go to Metrics Explorer + - Search for `test.datadog.integration` + - Set time range to "Last 1 hour" + - Look for metrics with tags: `service:lace-wallet, env:test` + +### Events Testing ✅ **VERIFIED** + +Events functionality has been tested and confirmed working: + +1. **Run the test workflow** to create test events +2. **Check Events Explorer**: https://us5.datadoghq.com/event/explorer +3. **Search for**: "Test Datadog CI Event" or "Minimal Test" +4. **Direct URLs**: Each event includes a direct link in the logs +5. **Expected Result**: Events appear with full metadata and direct access URLs + +### Debugging Tips + +- The test workflow provides detailed logging +- Check HTTP status codes (202 = success) +- Validate JSON payload with `jq` +- Monitor response times for performance issues + +## Files Created + +1. **`.github/workflows/test-datadog.yml`** - Test workflow for Datadog integration +2. **`.github/workflows/datadog-ci.yml`** - Reusable Datadog workflow +3. **`.github/workflows/ci-with-datadog.yml`** - CI with Datadog integration +4. **`docs/datadog-setup.md`** - This guide + +## Next Steps + +1. **Set up your Datadog account** and API key +2. **Add the secret** to GitHub +3. **Test the integration** using the test workflow +4. **Create dashboards** using the queries above +5. **Set up alerts** for critical failures +6. **Integrate with your main CI/CD** workflows + +## Support + +- [Datadog CI Documentation](https://docs.datadoghq.com/continuous_integration/) +- [GitHub Actions Integration](https://github.com/DataDog/github-action-metrics) +- [Datadog v2 API Reference](https://docs.datadoghq.com/api/latest/metrics/) diff --git a/docs/e2e-metrics-dashboard.json b/docs/e2e-metrics-dashboard.json new file mode 100644 index 0000000000..75b4c4a1a4 --- /dev/null +++ b/docs/e2e-metrics-dashboard.json @@ -0,0 +1,84 @@ +{ + "title": "Lace E2E Metrics Dashboard", + "description": "E2E test performance metrics dashboard", + "widgets": [ + { + "definition": { + "title": "E2E CPU Usage (seconds)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.e2e.cpu.seconds_total{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1" + } + ] + } + ], + "autoscale": true, + "precision": 2, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 0, + "y": 0, + "width": 2, + "height": 2 + } + }, + { + "definition": { + "title": "E2E Memory Usage (MB)", + "title_size": "16", + "title_align": "left", + "type": "query_value", + "requests": [ + { + "response_format": "scalar", + "queries": [ + { + "data_source": "metrics", + "name": "query1", + "query": "avg:lace.e2e.memory.rss_bytes{service:lace-wallet}", + "aggregator": "avg" + } + ], + "formulas": [ + { + "formula": "query1 / 1048576" + } + ] + } + ], + "autoscale": true, + "precision": 1, + "timeseries_background": { + "type": "area" + } + }, + "layout": { + "x": 2, + "y": 0, + "width": 2, + "height": 2 + } + } + ], + "template_variables": [], + "layout_type": "ordered", + "notify_list": [], + "reflow_type": "fixed" +} \ No newline at end of file diff --git a/find-datadog-org.sh b/find-datadog-org.sh new file mode 100755 index 0000000000..403191541b --- /dev/null +++ b/find-datadog-org.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# Find which Datadog organization this API key belongs to +echo "🔍 Finding Datadog Organization..." + +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY not set" + exit 1 +fi + +echo "✅ Using API Key: ${DATADOG_API_KEY:0:8}..." + +# Try different Datadog sites +sites=("datadoghq.com" "datadoghq.eu" "us3.datadoghq.com" "us5.datadoghq.com" "ap1.datadoghq.com") + +for site in "${sites[@]}"; do + echo "" + echo "🌐 Testing site: $site" + + # Test metrics endpoint + response=$(curl -s -w "%{http_code}" -X POST "https://api.$site/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.site.check", + "points": [[$(date +%s), 1]], + "tags": ["site:'$site'"], + "type": "gauge" + }] + }') + + http_code="${response: -3}" + response_body="${response%???}" + + echo "HTTP Code: $http_code" + echo "Response: $response_body" + + if [ "$http_code" = "202" ]; then + echo "✅ SUCCESS! This API key works with $site" + echo "" + echo "🎯 Go to: https://app.$site" + echo "📊 Look for metric: test.site.check" + echo "🏷️ Filter by tag: site:$site" + break + else + echo "❌ Failed with $site" + fi +done + +echo "" +echo "🔍 If none of the sites work, try:" +echo "1. Check your Datadog account settings" +echo "2. Verify the API key is for the correct organization" +echo "3. Contact your Datadog admin" \ No newline at end of file diff --git a/find-datadog-site.sh b/find-datadog-site.sh new file mode 100755 index 0000000000..305b553a75 --- /dev/null +++ b/find-datadog-site.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +echo "🔍 Finding your Datadog site..." + +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY not set" + exit 1 +fi + +echo "✅ Using API Key: ${DATADOG_API_KEY:0:8}..." + +# Test different Datadog sites +sites=("datadoghq.com" "us3.datadoghq.com" "us5.datadoghq.com" "ap1.datadoghq.com" "datadoghq.eu") + +for site in "${sites[@]}"; do + echo "" + echo "🌐 Testing site: $site" + + # Test metrics endpoint + response=$(curl -s -w "%{http_code}" -X POST "https://api.$site/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.site.check", + "points": [[$(date +%s), 1]], + "tags": ["site:'$site'"], + "type": "gauge" + }] + }') + + http_code="${response: -3}" + response_body="${response%???}" + + echo "HTTP Code: $http_code" + echo "Response: $response_body" + + if [ "$http_code" = "202" ]; then + echo "✅ SUCCESS! This API key works with $site" + echo "" + echo "🎯 Go to: https://app.$site" + echo "📊 Look for metric: test.site.check" + echo "🏷️ Filter by tag: site:$site" + break + else + echo "❌ Failed with $site" + fi +done + +echo "" +echo "🔍 If none of the sites work, try:" +echo "1. Check your Datadog account settings" +echo "2. Verify the API key is for the correct organization" +echo "3. Contact your Datadog admin" \ No newline at end of file diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 9c092ebdbb..adedd401c4 100755 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -10,7 +10,7 @@ "allure:generate": "yarn allure generate -c ./reports/allure/results -o ./reports/allure/report", "allure:open": "allure open ./reports/allure/report/", "build": "yarn exec echo 'No build required'", - "cleanup": "rm -rf logs node_modules reports screenshots", + "cleanup": "rm -rf logs node_modules reports screenshots metrics", "lint": "run -T eslint -c .eslintrc.cjs .", "lint:fix": "run -T eslint -c .eslintrc.cjs . --fix", "pack-chrome-extension": "node ./src/utils/packExtension.ts", diff --git a/packages/e2e-tests/src/support/PidMonitor.ts b/packages/e2e-tests/src/support/PidMonitor.ts index d0190330e4..92bb4df47d 100644 --- a/packages/e2e-tests/src/support/PidMonitor.ts +++ b/packages/e2e-tests/src/support/PidMonitor.ts @@ -9,7 +9,7 @@ import { Logger } from './logger'; const execAsync = promisify(exec); interface UsageData { - timestamp: string; + timestamp: number; cpu: number; memory: number; } @@ -81,7 +81,7 @@ class PidMonitor { try { const stats = await pidusage(this.pid); this._data.push({ - timestamp: new Date().toISOString(), + timestamp: Date.now(), cpu: stats.cpu, memory: stats.memory }); diff --git a/packages/e2e-tests/tools/convertChromeExtToSafari.sh b/packages/e2e-tests/tools/convertChromeExtToSafari.sh deleted file mode 100644 index 9067ae3589..0000000000 --- a/packages/e2e-tests/tools/convertChromeExtToSafari.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -EXTENSION_DIR=../../apps/browser-extension-wallet -EXTENSION_BUILD_DIR="$EXTENSION_DIR/dist" -SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH=./wallet-extension-safari-build -SAFARI_BUILT_EXTENSION_DIR="$SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH/extension-build" -SAFARI_DEBUG_BUILD_PATH="$SAFARI_BUILT_EXTENSION_DIR/Build/Products/Release" - -if [ ! -d $EXTENSION_BUILD_DIR ]; then - echo "Could not find web extension build. Please build extension first" - exit -fi - -xcrun safari-web-extension-converter $EXTENSION_BUILD_DIR --no-prompt --copy-resources --no-open --project-location $SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH --bundle-identifier io.lace.Lace - -cd "$SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH/Lace" - -xcodebuild -configuration Release -scheme "Lace (macOS)" -derivedDataPath $SAFARI_BUILT_EXTENSION_DIR diff --git a/packages/e2e-tests/tools/convert_metrics_to_datadog.sh b/packages/e2e-tests/tools/convert_metrics_to_datadog.sh new file mode 100755 index 0000000000..24fb592c6f --- /dev/null +++ b/packages/e2e-tests/tools/convert_metrics_to_datadog.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +set -euo pipefail + +JOB=${1:-} +INSTANCE=${2:-} +METRICS_DIR=${3:-metrics} +DATADOG_API_KEY=${4:-} + +if [[ -z "$JOB" || -z "$INSTANCE" ]]; then + echo "Usage: $0 [metrics_dir] [datadog_api_key]" + echo " job - GitHub workflow name" + echo " instance - GitHub run ID" + echo " metrics_dir - (optional) Directory containing JSON metrics files (default: metrics)" + echo " datadog_api_key - (optional) Datadog API key for direct sending" + exit 1 +fi + +if [[ ! -d "$METRICS_DIR" ]]; then + echo "Metrics directory '$METRICS_DIR' does not exist." + exit 0 +fi + +shopt -s nullglob +FILES=("$METRICS_DIR"/*.json) + +if [[ ${#FILES[@]} -eq 0 ]]; then + echo "No JSON files found in '$METRICS_DIR'." + exit 0 +fi + +# Prepare Datadog payload +TIMESTAMP=$(date +%s) +SERIES=() + +for file in "${FILES[@]}"; do + if [[ ! -s "$file" ]]; then + echo "Skipping empty file: $file" + continue + fi + + # Validate JSON file + if ! jq empty "$file" 2>/dev/null; then + echo "Warning: Invalid JSON in $file, skipping" + continue + fi + + filename=$(basename "$file") + scenario_id="${filename%%-chrome-usage.json}" + + # Better JSON escaping using jq + scenario_name=$(jq -r '.scenarioName // empty' "$file" | jq -Rs . | sed 's/^"//;s/"$//') + + data_length=$(jq '.data | length' "$file") + + echo "Processing $filename (scenario: $scenario_name, data points: $data_length)" + + if [[ "$data_length" -eq 0 ]]; then + # Add zero values if no data + SERIES+=("{ + \"metric\": \"lace.e2e.cpu.seconds_total\", + \"points\": [{\"timestamp\": $TIMESTAMP, \"value\": 0}], + \"tags\": [\"scenario_name:$scenario_name\", \"scenario_id:$scenario_id\", \"job:$JOB\", \"instance:$INSTANCE\"] + }") + SERIES+=("{ + \"metric\": \"lace.e2e.memory.rss_bytes\", + \"points\": [{\"timestamp\": $TIMESTAMP, \"value\": 0}], + \"tags\": [\"scenario_name:$scenario_name\", \"scenario_id:$scenario_id\", \"job:$JOB\", \"instance:$INSTANCE\"] + }") + else + # Process each data point - avoid subshell issues + while IFS= read -r entry; do + timestamp=$(echo "$entry" | jq -r '.timestamp') + cpu=$(echo "$entry" | jq -r '.cpu') + memory=$(echo "$entry" | jq -r '.memory') + + # Better timestamp handling + if [[ "$timestamp" =~ ^[0-9]{10}$ ]]; then + # 10 digits - likely Unix timestamp (seconds) + unix_timestamp=$timestamp + elif [[ "$timestamp" =~ ^[0-9]{13}$ ]]; then + # 13 digits - likely Unix timestamp (milliseconds) + unix_timestamp=$((timestamp / 1000)) + else + # Unknown format, use current time + unix_timestamp=$TIMESTAMP + fi + + # Validate numeric values + if [[ "$cpu" =~ ^[0-9]+\.?[0-9]*$ ]] && [[ "$memory" =~ ^[0-9]+\.?[0-9]*$ ]]; then + SERIES+=("{ + \"metric\": \"lace.e2e.cpu.seconds_total\", + \"points\": [{\"timestamp\": $unix_timestamp, \"value\": $cpu}], + \"tags\": [\"scenario_name:$scenario_name\", \"scenario_id:$scenario_id\", \"job:$JOB\", \"instance:$INSTANCE\"] + }") + SERIES+=("{ + \"metric\": \"lace.e2e.memory.rss_bytes\", + \"points\": [{\"timestamp\": $unix_timestamp, \"value\": $memory}], + \"tags\": [\"scenario_name:$scenario_name\", \"scenario_id:$scenario_id\", \"job:$JOB\", \"instance:$INSTANCE\"] + }") + else + echo "Warning: Invalid numeric values in $file (cpu: $cpu, memory: $memory)" + fi + done < <(jq -c '.data[]' "$file") + fi +done + +# Check if we have any metrics +if [[ ${#SERIES[@]} -eq 0 ]]; then + echo "No valid metrics found to send" + exit 0 +fi + +# Create the final payload +PAYLOAD="{ + \"series\": [$(IFS=,; echo "${SERIES[*]}")] +}" + +echo "Generated Datadog payload with ${#SERIES[@]} metrics" + +# Save payload to file for debugging +echo "$PAYLOAD" > "$METRICS_DIR/datadog_payload.json" +echo "Datadog payload saved to: $METRICS_DIR/datadog_payload.json" + +# Send to Datadog if API key provided +if [[ -n "$DATADOG_API_KEY" ]]; then + echo "Sending metrics to Datadog..." + + # Validate payload JSON + if ! echo "$PAYLOAD" | jq empty 2>/dev/null; then + echo "❌ ERROR: Invalid JSON payload generated" + exit 1 + fi + + response=$(curl -s -w "\nHTTP_STATUS_CODE:%{http_code}\nTOTAL_TIME:%{time_total}s\n" \ + -X POST "https://api.us5.datadoghq.com/api/v2/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d "@$METRICS_DIR/datadog_payload.json") + + http_code=$(echo "$response" | grep "HTTP_STATUS_CODE:" | cut -d: -f2) + total_time=$(echo "$response" | grep "TOTAL_TIME:" | cut -d: -f2) + response_body=$(echo "$response" | sed '/HTTP_STATUS_CODE:/d' | sed '/TOTAL_TIME:/d') + + echo "Datadog API Response:" + echo " Status: $http_code" + echo " Time: ${total_time}s" + echo " Body: $response_body" + + if [[ "$http_code" = "202" ]]; then + echo "✅ SUCCESS: E2E metrics sent to Datadog!" + else + echo "❌ ERROR: Failed to send E2E metrics to Datadog" + echo " Response: $response_body" + exit 1 + fi +else + echo "No Datadog API key provided, metrics saved to file only" +fi \ No newline at end of file diff --git a/packages/e2e-tests/tools/convert_metrics_to_prometheus.sh b/packages/e2e-tests/tools/convert_metrics_to_prometheus.sh new file mode 100755 index 0000000000..1f2274870d --- /dev/null +++ b/packages/e2e-tests/tools/convert_metrics_to_prometheus.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +set -euo pipefail + +JOB=${1:-} +INSTANCE=${2:-} +METRICS_DIR=${3:-metrics} + +if [[ -z "$JOB" || -z "$INSTANCE" ]]; then + echo "Usage: $0 [metrics_dir]" + echo " job - GitHub workflow name" + echo " instance - GitHub run ID" + echo " metrics_dir - (optional) Directory containing JSON metrics files (default: metrics)" + exit 1 +fi + +OUTPUT_FILE="$METRICS_DIR/prometheus.txt" + +if [[ ! -d "$METRICS_DIR" ]]; then + echo "Metrics directory '$METRICS_DIR' does not exist." + exit 0 +fi + +shopt -s nullglob +FILES=("$METRICS_DIR"/*.json) + +# Filter out the output file from being processed +FILES=("${FILES[@]/$OUTPUT_FILE}") + +if [[ ${#FILES[@]} -eq 0 ]]; then + echo "No JSON files found in '$METRICS_DIR'." + exit 0 +fi + +> "$OUTPUT_FILE" + +for file in "${FILES[@]}"; do + if [[ ! -s "$file" ]]; then + echo "Skipping empty file: $file" + continue + fi + + filename=$(basename "$file") + scenario_id="${filename%%-chrome-usage.json}" + scenario_name=$(jq -r '.scenarioName // empty' "$file" | sed 's/"/\\"/g') + data_length=$(jq '.data | length' "$file") + + echo "# Metrics from $filename" >> "$OUTPUT_FILE" + + if [[ "$data_length" -eq 0 ]]; then + echo "e2e_cpu_seconds_total{scenario_name=\"$scenario_name\",scenario_id=\"$scenario_id\",job=\"$JOB\",instance=\"$INSTANCE\"} 0" >> "$OUTPUT_FILE" + echo "e2e_memory_rss_bytes{scenario_name=\"$scenario_name\",scenario_id=\"$scenario_id\",job=\"$JOB\",instance=\"$INSTANCE\"} 0" >> "$OUTPUT_FILE" + else + jq -c '.data[]' "$file" | while read -r entry; do + timestamp=$(echo "$entry" | jq -r '.timestamp') + cpu=$(echo "$entry" | jq -r '.cpu') + memory=$(echo "$entry" | jq -r '.memory') + + echo "e2e_cpu_seconds_total{scenario_name=\"$scenario_name\",scenario_id=\"$scenario_id\",job=\"$JOB\",instance=\"$INSTANCE\",timestamp=\"$timestamp\"} $cpu" >> "$OUTPUT_FILE" + echo "e2e_memory_rss_bytes{scenario_name=\"$scenario_name\",scenario_id=\"$scenario_id\",job=\"$JOB\",instance=\"$INSTANCE\",timestamp=\"$timestamp\"} $memory" >> "$OUTPUT_FILE" + done + fi +done + +echo "Metrics converted to Prometheus format: $OUTPUT_FILE" diff --git a/packages/e2e-tests/tools/openSafariExtension.sh b/packages/e2e-tests/tools/openSafariExtension.sh deleted file mode 100644 index fda8d696b2..0000000000 --- a/packages/e2e-tests/tools/openSafariExtension.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH=./wallet-extension-safari-build -SAFARI_BUILT_EXTENSION_DIR="$SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH/extension-build" -SAFARI_DEBUG_BUILD_PATH="$SAFARI_BUILT_EXTENSION_DIR/Build/Products/Release" - -cd "$SAFARI_EXTENSION_OUTPUT_RELATIVE_PATH/Lace" -open -n "$SAFARI_DEBUG_BUILD_PATH/Lace.app" diff --git a/send-test-metric.sh b/send-test-metric.sh new file mode 100755 index 0000000000..3b21c08aca --- /dev/null +++ b/send-test-metric.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Send a test metric that's easy to find in Datadog +echo "Sending a test metric to Datadog..." + +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY not set. Please set it first:" + echo "export DATADOG_API_KEY=your_api_key_here" + exit 1 +fi + +# Send a simple test metric +response=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "lace.test.metric", + "points": [[$(date +%s), 42]], + "tags": ["service:lace-wallet", "env:test", "test:manual"], + "type": "gauge" + }] + }') + +http_code="${response: -3}" +response_body="${response%???}" + +echo "HTTP Status Code: $http_code" +echo "Response: $response_body" + +if [ "$http_code" = "202" ]; then + echo "✅ Success! Test metric sent to Datadog" + echo "" + echo "🔍 To find this metric in Datadog:" + echo "1. Go to Metrics → Explorer" + echo "2. Search for: lace.test.metric" + echo "3. Or filter by: service:lace-wallet" + echo "" + echo "📊 Metric details:" + echo " Name: lace.test.metric" + echo " Value: 42" + echo " Tags: service:lace-wallet, env:test, test:manual" + echo " Type: gauge" +else + echo "❌ Failed to send metric" + echo "HTTP Code: $http_code" + echo "Response: $response_body" +fi \ No newline at end of file diff --git a/test-both-keys.sh b/test-both-keys.sh new file mode 100644 index 0000000000..e819c83c54 --- /dev/null +++ b/test-both-keys.sh @@ -0,0 +1,147 @@ +#!/bin/bash + +# Test both API keys to see which one works better +echo "Testing both Datadog API keys..." + +# Check if both keys are set +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY not set" + echo "Please set it with: export DATADOG_API_KEY=your_regular_key" + exit 1 +fi + +if [ -z "$DATADOG_EVENT_KEY" ]; then + echo "❌ DATADOG_EVENT_KEY not set" + echo "Please set it with: export DATADOG_EVENT_KEY=your_event_migration_key" + exit 1 +fi + +echo "✅ Both API keys are set" + +# Test 1: Regular API Key - Metrics +echo "" +echo "🔑 Testing Regular API Key (Metrics)..." +response1=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "lace.test.regular_key", + "points": [[$(date +%s), 100]], + "tags": ["service:lace-wallet", "env:test", "key:regular"], + "type": "gauge" + }] + }') + +http_code1="${response1: -3}" +response_body1="${response1%???}" + +echo "HTTP Status Code: $http_code1" +echo "Response: $response_body1" + +if [ "$http_code1" = "202" ]; then + echo "✅ Regular key works for metrics" +else + echo "❌ Regular key failed for metrics" +fi + +# Test 2: Event Migration Key - Metrics +echo "" +echo "🔑 Testing Event Migration Key (Metrics)..." +response2=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_EVENT_KEY" \ + -d '{ + "series": [{ + "metric": "lace.test.event_key", + "points": [[$(date +%s), 200]], + "tags": ["service:lace-wallet", "env:test", "key:event_migration"], + "type": "gauge" + }] + }') + +http_code2="${response2: -3}" +response_body2="${response2%???}" + +echo "HTTP Status Code: $http_code2" +echo "Response: $response_body2" + +if [ "$http_code2" = "202" ]; then + echo "✅ Event migration key works for metrics" +else + echo "❌ Event migration key failed for metrics" +fi + +# Test 3: Regular API Key - Events +echo "" +echo "🔑 Testing Regular API Key (Events)..." +event_response1=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "title": "Test Event - Regular Key", + "text": "Testing event sending with regular API key", + "tags": ["service:lace-wallet", "env:test", "key:regular"], + "alert_type": "info", + "source_type_name": "github" + }') + +event_http_code1="${event_response1: -3}" +event_response_body1="${event_response1%???}" + +echo "HTTP Status Code: $event_http_code1" +echo "Response: $event_response_body1" + +if [ "$event_http_code1" = "202" ]; then + echo "✅ Regular key works for events" +else + echo "❌ Regular key failed for events" +fi + +# Test 4: Event Migration Key - Events +echo "" +echo "🔑 Testing Event Migration Key (Events)..." +event_response2=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_EVENT_KEY" \ + -d '{ + "title": "Test Event - Event Migration Key", + "text": "Testing event sending with event migration key", + "tags": ["service:lace-wallet", "env:test", "key:event_migration"], + "alert_type": "info", + "source_type_name": "github" + }') + +event_http_code2="${event_response2: -3}" +event_response_body2="${event_response2%???}" + +echo "HTTP Status Code: $event_http_code2" +echo "Response: $event_response_body2" + +if [ "$event_http_code2" = "202" ]; then + echo "✅ Event migration key works for events" +else + echo "❌ Event migration key failed for events" +fi + +# Summary +echo "" +echo "📊 SUMMARY:" +echo "Regular Key - Metrics: $([ "$http_code1" = "202" ] && echo "✅" || echo "❌")" +echo "Event Key - Metrics: $([ "$http_code2" = "202" ] && echo "✅" || echo "❌")" +echo "Regular Key - Events: $([ "$event_http_code1" = "202" ] && echo "✅" || echo "❌")" +echo "Event Key - Events: $([ "$event_http_code2" = "202" ] && echo "✅" || echo "❌")" + +echo "" +echo "🎯 RECOMMENDATION:" +if [ "$http_code1" = "202" ] && [ "$event_http_code1" = "202" ]; then + echo "Use the REGULAR API key - it works for both metrics and events" +elif [ "$http_code2" = "202" ] && [ "$event_http_code2" = "202" ]; then + echo "Use the EVENT MIGRATION key - it works for both metrics and events" +elif [ "$http_code1" = "202" ]; then + echo "Use the REGULAR API key for metrics, EVENT MIGRATION key for events" +elif [ "$http_code2" = "202" ]; then + echo "Use the EVENT MIGRATION key for metrics, REGULAR API key for events" +else + echo "❌ Neither key seems to work properly. Check your API keys." +fi \ No newline at end of file diff --git a/test-datadog.sh b/test-datadog.sh new file mode 100755 index 0000000000..030e45770e --- /dev/null +++ b/test-datadog.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +# Test Datadog API Key +echo "Testing Datadog API Key..." + +# Check if DATADOG_API_KEY is set +if [ -z "$DATADOG_API_KEY" ]; then + echo "❌ DATADOG_API_KEY environment variable is not set" + echo "Please set it with: export DATADOG_API_KEY=your_personal_api_key_here" + exit 1 +fi + +echo "✅ DATADOG_API_KEY is set" + +# Test API key by sending a simple metric +echo "📊 Sending test metric to Datadog..." + +response=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.lace.ci.connection", + "points": [[$(date +%s), 1]], + "tags": ["service:lace-wallet", "env:test", "test:api-connection"], + "type": "gauge" + }] + }') + +http_code="${response: -3}" +response_body="${response%???}" + +echo "HTTP Status Code: $http_code" +echo "Response: $response_body" + +if [ "$http_code" = "202" ]; then + echo "✅ Success! Metric sent to Datadog" + echo "Check your Datadog dashboard for metric: test.lace.ci.connection" +else + echo "❌ Failed to send metric to Datadog" + echo "HTTP Code: $http_code" + echo "Response: $response_body" +fi + +# Test events API +echo "📝 Testing Datadog Events API..." + +event_response=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_API_KEY" \ + -d '{ + "title": "Lace CI Test Event", + "text": "This is a test event from Lace CI integration", + "tags": ["service:lace-wallet", "env:test", "test:event"], + "alert_type": "info", + "source_type_name": "github" + }') + +event_http_code="${event_response: -3}" +event_response_body="${event_response%???}" + +echo "Events HTTP Status Code: $event_http_code" +echo "Events Response: $event_response_body" + +if [ "$event_http_code" = "202" ]; then + echo "✅ Success! Event sent to Datadog" +else + echo "❌ Failed to send event to Datadog" + echo "HTTP Code: $event_http_code" + echo "Response: $event_response_body" +fi diff --git a/test-permissions.sh b/test-permissions.sh new file mode 100755 index 0000000000..6e316e5835 --- /dev/null +++ b/test-permissions.sh @@ -0,0 +1,134 @@ +#!/bin/bash + +# Test Datadog API Key Permissions +echo "🔍 Testing Datadog API Key Permissions..." + +if [ -z "$DATADOG_P_API_KEY" ]; then + echo "❌ DATADOG_P_API_KEY not set" + echo "Please set it with: export DATADOG_P_API_KEY=your_personal_api_key_here" + exit 1 +fi + +echo "✅ Using API Key: ${DATADOG_P_API_KEY:0:8}..." + +# Test 1: Check if we can send metrics (this is the key test) +echo "" +echo "📊 Test 1: Can we send metrics?" +response1=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/series" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_P_API_KEY" \ + -d '{ + "series": [{ + "metric": "test.permissions.metrics", + "points": [[$(date +%s), 1]], + "tags": ["test:permissions"], + "type": "gauge" + }] + }') + +http_code1="${response1: -3}" +response_body1="${response1%???}" + +echo "HTTP Code: $http_code1" +echo "Response: $response_body1" + +if [ "$http_code1" = "202" ]; then + echo "✅ SUCCESS! Can send metrics" +elif [ "$http_code1" = "403" ]; then + echo "❌ FORBIDDEN! No permission to send metrics" +elif [ "$http_code1" = "401" ]; then + echo "❌ UNAUTHORIZED! Invalid API key" +else + echo "❓ UNKNOWN! HTTP $http_code1 - $response_body1" +fi + +# Test 2: Check if we can read metrics +echo "" +echo "📊 Test 2: Can we read metrics?" +response2=$(curl -s -w "%{http_code}" -X GET "https://api.datadoghq.com/api/v1/query?from=$(date -d '1 hour ago' +%s)&to=$(date +%s)&query=test.permissions.metrics" \ + -H "DD-API-KEY: $DATADOG_P_API_KEY") + +http_code2="${response2: -3}" +response_body2="${response2%???}" + +echo "HTTP Code: $http_code2" +echo "Response: $response_body2" + +if [ "$http_code2" = "200" ]; then + echo "✅ SUCCESS! Can read metrics" +elif [ "$http_code2" = "403" ]; then + echo "❌ FORBIDDEN! No permission to read metrics" +elif [ "$http_code2" = "401" ]; then + echo "❌ UNAUTHORIZED! Invalid API key" +else + echo "❓ UNKNOWN! HTTP $http_code2" +fi + +# Test 3: Check if we can send events +echo "" +echo "📝 Test 3: Can we send events?" +response3=$(curl -s -w "%{http_code}" -X POST "https://api.datadoghq.com/api/v1/events" \ + -H "Content-Type: application/json" \ + -H "DD-API-KEY: $DATADOG_P_API_KEY" \ + -d '{ + "title": "Test Permissions Event", + "text": "Testing event permissions", + "tags": ["test:permissions"], + "alert_type": "info" + }') + +http_code3="${response3: -3}" +response_body3="${response3%???}" + +echo "HTTP Code: $http_code3" +echo "Response: $response_body3" + +if [ "$http_code3" = "202" ]; then + echo "✅ SUCCESS! Can send events" +elif [ "$http_code3" = "403" ]; then + echo "❌ FORBIDDEN! No permission to send events" +elif [ "$http_code3" = "401" ]; then + echo "❌ UNAUTHORIZED! Invalid API key" +else + echo "❓ UNKNOWN! HTTP $http_code3" +fi + +# Test 4: Check user info +echo "" +echo "👤 Test 4: Can we get user info?" +response4=$(curl -s -w "%{http_code}" -X GET "https://api.datadoghq.com/api/v1/user" \ + -H "DD-API-KEY: $DATADOG_P_API_KEY") + +http_code4="${response4: -3}" +response_body4="${response4%???}" + +echo "HTTP Code: $http_code4" +if [ "$http_code4" = "200" ]; then + echo "✅ SUCCESS! Can get user info" + echo "User info: $response_body4" +elif [ "$http_code4" = "403" ]; then + echo "❌ FORBIDDEN! No permission to get user info" +elif [ "$http_code4" = "401" ]; then + echo "❌ UNAUTHORIZED! Invalid API key" +else + echo "❓ UNKNOWN! HTTP $http_code4" +fi + +# Summary +echo "" +echo "📊 PERMISSIONS SUMMARY:" +echo "Send Metrics: $([ "$http_code1" = "202" ] && echo "✅" || echo "❌")" +echo "Read Metrics: $([ "$http_code2" = "200" ] && echo "✅" || echo "❌")" +echo "Send Events: $([ "$http_code3" = "202" ] && echo "✅" || echo "❌")" +echo "Get User Info: $([ "$http_code4" = "200" ] && echo "✅" || echo "❌")" + +echo "" +echo "🎯 RECOMMENDATIONS:" +if [ "$http_code1" = "202" ]; then + echo "✅ Your API key CAN send metrics - this is what we need!" +elif [ "$http_code1" = "403" ]; then + echo "❌ Your API key CANNOT send metrics - you need 'metrics_write' permission" + echo " Contact your Datadog admin to get this permission" +elif [ "$http_code1" = "401" ]; then + echo "❌ Invalid API key - check your key" +fi \ No newline at end of file