Skip to content

Capture Android emulator logcat output - #3627

Draft
sjchmiela wants to merge 12 commits into
mainfrom
stanley/eng-20762-stage-emulator-logcat
Draft

Capture Android emulator logcat output#3627
sjchmiela wants to merge 12 commits into
mainfrom
stanley/eng-20762-stage-emulator-logcat

Conversation

@sjchmiela

@sjchmiela sjchmiela commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Why

Workflow Maestro tests currently collect Android logs with adb logcat after the tests. This depends on the ADB server and can lose logs when ADB becomes unavailable.

How

  • Start each Android Emulator with native -logcat '*:v' and -logcat-output arguments.
  • Write logs to a unique temporary directory that lasts for the job.
  • Expose that directory as the logcat_directory output of eas/start_android_emulator.
  • Leave artifact collection and upload to workflow consumers.

The matching expo/universe change copies this output into the Maestro test-results directory before the existing artifact upload.

Test Plan

  • yarn workspace @expo/build-tools jest-unit src/steps/functions/__tests__/startAndroidEmulator.test.ts src/utils/__tests__/AndroidEmulatorUtils.test.ts --runInBand
  • yarn workspace @expo/build-tools typecheck
  • yarn fmt:check
  • Real-emulator integration test confirms native logcat capture continues across an ADB server restart.

@linear

linear Bot commented Apr 23, 2026

Copy link
Copy Markdown

@codecov

codecov Bot commented Apr 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.56%. Comparing base (42a487e) to head (6f014a3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3627      +/-   ##
==========================================
+ Coverage   62.50%   62.56%   +0.07%     
==========================================
  Files        1008     1008              
  Lines       45815    45864      +49     
  Branches     9649     9655       +6     
==========================================
+ Hits        28630    28691      +61     
+ Misses      15724    15714      -10     
+ Partials     1461     1459       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sjchmiela
sjchmiela force-pushed the stanley/eng-20762-stage-emulator-logcat branch 2 times, most recently from 7945c7d to 6c0f797 Compare April 23, 2026 15:56
@sjchmiela
sjchmiela requested a review from Copilot April 24, 2026 11:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds early, continuous Android emulator logcat capture during eas/start_android_emulator so logs are preserved even if the emulator dies before later diagnostics can run.

Changes:

  • Introduces a build-logs staging directory for Android emulator logcat output.
  • Starts adb logcat -v threadtime streaming immediately after each emulator boot and writes output to staged files.
  • Adds/updates unit tests for the new streaming behavior and step integration.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
packages/build-tools/src/utils/AndroidEmulatorUtils.ts Adds logcat staging path helper and startLogcatStreamingAsync implementation.
packages/build-tools/src/steps/functions/startAndroidEmulator.ts Starts logcat streaming for each emulator (including clones) using the build logs staging directory.
packages/build-tools/src/utils/tests/AndroidEmulatorUtils.test.ts Adds unit tests for logcat streaming success/failure.
packages/build-tools/src/steps/functions/tests/startAndroidEmulator.test.ts Updates mocks/assertions to cover logcat streaming integration and failure tolerance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/build-tools/src/utils/AndroidEmulatorUtils.ts Outdated
Comment on lines +525 to +547
const safeSerialId = serialId.replace(/[^a-zA-Z0-9_.-]/g, '_');
const outputPath = path.join(outputDir, `${child.pid}-${safeSerialId}.log`);
const writeStream = fs.createWriteStream(outputPath);
child.stdout.pipe(writeStream);
child.stdout.on('error', err => {
logger.warn({ err }, `Failed to read Android emulator logcat for ${serialId}.`);
});
writeStream.on('error', err => {
logger.warn({ err }, `Failed to write Android emulator logcat for ${serialId}.`);
});
child.on('close', () => {
writeStream.end();
});
child.unref();

void logcatPromise.catch(err => {
logger.warn({ err }, `Android emulator logcat stream for ${serialId} stopped.`);
});

logger.info(`Streaming Android emulator logcat for ${serialId} to ${outputPath}.`);

return { outputPath };
} catch (err) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping this as-is intentionally. We split the work so PR 1 only starts staging logcat for every emulator, and PR 2 only copies the staged .log files into Maestro artifacts. The collection step no longer stops logcat or needs per-stream metadata, so returning outputPath is enough for this branch and avoids reintroducing the metadata/stop path we explicitly removed in the follow-up PR.

Comment thread packages/build-tools/src/utils/__tests__/AndroidEmulatorUtils.test.ts Outdated
Comment thread packages/build-tools/src/utils/__tests__/AndroidEmulatorUtils.test.ts Outdated
Comment thread packages/build-tools/src/utils/__tests__/AndroidEmulatorUtils.test.ts Outdated
@sjchmiela
sjchmiela requested a review from Copilot April 24, 2026 11:50
@sjchmiela sjchmiela added the no changelog PR that doesn't require a changelog entry label Apr 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds best-effort, continuous adb logcat streaming for Android emulators started by the eas/start_android_emulator build function, writing output into a predictable subdirectory under the build logs directory so logs are preserved even if the emulator disappears later.

Changes:

  • Added AndroidEmulatorUtils.startLogcatStreamingAsync to start adb logcat -v threadtime streaming into a staged .log file.
  • Added AndroidEmulatorUtils.getLogcatStagingDirectoryPath and wired it into eas/start_android_emulator so every started emulator begins streaming logcat immediately.
  • Added/updated unit tests covering the streaming behavior and the build function integration.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/build-tools/src/utils/AndroidEmulatorUtils.ts Adds logcat staging path helper and a new async helper to start streaming logcat to a file.
packages/build-tools/src/utils/tests/AndroidEmulatorUtils.test.ts Adds tests validating logcat streaming writes to a staged file and handles spawn failures.
packages/build-tools/src/steps/functions/startAndroidEmulator.ts Starts logcat streaming for base emulators and clones immediately after each startAsync.
packages/build-tools/src/steps/functions/tests/startAndroidEmulator.test.ts Updates mocks/assertions to verify logcat streaming is invoked during emulator startup and failures don’t block readiness waits.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/build-tools/src/utils/AndroidEmulatorUtils.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds early, continuous Android emulator adb logcat streaming to a predictable staging directory under the build logs directory so logs are preserved even if the emulator crashes before later diagnostics.

Changes:

  • Add AndroidEmulatorUtils.getLogcatStagingDirectoryPath() and AndroidEmulatorUtils.startLogcatStreamingAsync() to start and persist logcat streaming to disk.
  • Invoke logcat streaming during base emulator startup and during clone startup in eas/start_android_emulator.
  • Add unit tests for the new utility and update startAndroidEmulator step tests to assert logcat streaming behavior and ordering.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
packages/build-tools/src/utils/tests/AndroidEmulatorUtils.test.ts Adds tests for startLogcatStreamingAsync and temp-dir cleanup.
packages/build-tools/src/utils/AndroidEmulatorUtils.ts Introduces logcat staging path helper and streaming implementation.
packages/build-tools/src/steps/functions/startAndroidEmulator.ts Starts logcat streaming as part of emulator bring-up (base + clones).
packages/build-tools/src/steps/functions/tests/startAndroidEmulator.test.ts Extends step tests to cover logcat streaming calls and failure tolerance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/build-tools/src/utils/AndroidEmulatorUtils.ts Outdated
Comment thread packages/build-tools/src/utils/__tests__/AndroidEmulatorUtils.test.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds continuous adb logcat streaming for Android emulators started by the eas/start_android_emulator build function, staging log output under the build logs directory so logs survive emulator crashes.

Changes:

  • Add AndroidEmulatorUtils.getLogcatStagingDirectoryPath() and startLogcatStreamingAsync() to stream adb logcat -v threadtime into staged files.
  • Wire logcat streaming into the emulator startup flow (including cloned emulators).
  • Add unit tests for the new utility and update step tests to assert streaming is invoked before readiness checks and that failures don’t block startup.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/build-tools/src/utils/AndroidEmulatorUtils.ts Introduces staging path helper and logcat streaming implementation.
packages/build-tools/src/steps/functions/startAndroidEmulator.ts Starts logcat streaming immediately after emulator start (base + clones) using the build logs directory.
packages/build-tools/src/utils/tests/AndroidEmulatorUtils.test.ts Adds unit coverage for streaming success and failure paths.
packages/build-tools/src/steps/functions/tests/startAndroidEmulator.test.ts Verifies streaming is invoked for each emulator and does not block startup when it fails.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const childStdout = child.stdout;
const safeSerialId = serialId.replace(/[^a-zA-Z0-9_.-]/g, '_');
const outputPath = path.join(outputDir, `${child.pid}-${safeSerialId}.log`);
const writeStream = fs.createWriteStream(outputPath);
@sjchmiela
sjchmiela force-pushed the stanley/eng-20762-stage-emulator-logcat branch 2 times, most recently from 7903f38 to c9deda0 Compare August 7, 2026 20:27
@sjchmiela sjchmiela changed the title Stage Android emulator logcat output Capture Android emulator logcat output Aug 7, 2026
@sjchmiela
sjchmiela changed the base branch from main to stanley/upload-artifact-copy-before-upload August 7, 2026 20:27
@sjchmiela
sjchmiela force-pushed the stanley/eng-20762-stage-emulator-logcat branch from c9deda0 to 968a67e Compare August 7, 2026 20:30
@sjchmiela
sjchmiela force-pushed the stanley/eng-20762-stage-emulator-logcat branch from 968a67e to 6f014a3 Compare August 7, 2026 21:03
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

⏩ The changelog entry check has been skipped since the "no changelog" label is present.

@sjchmiela
sjchmiela changed the base branch from stanley/upload-artifact-copy-before-upload to main August 7, 2026 21:03
@sjchmiela
sjchmiela requested a lite review from Copilot August 7, 2026 21:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/build-tools/src/utils/tests/AndroidEmulatorUtils.test.ts:106

  • This assertion uses rejects.toEqual(new SystemError(..., { cause })), but Jest’s error equality often compares only name/message and may ignore non-enumerable fields like cause. That means the test may pass even if the thrown SystemError does not actually preserve mkdirError as its cause. Prefer asserting the error type/message and separately matching cause on the rejected error object.
        ).rejects.toEqual(
          new SystemError('Failed to prepare Android emulator logcat output for eas-simulator.', {
            cause: mkdirError,
          })
        );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog PR that doesn't require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants