skip to content

Why can one Appium log configuration not serve an Android and an iOS lane, and what do you standardise?

level: principalimportance: should knowfreq 31%

answer

  1. process configuration versus session vocabulary
  2. the route is shared, the names are not
  3. standardise flags, discover buckets
  4. keep the platform branch in one place

basics

~20 s

Appium's logging has two halves. Server flags such as --log-level and --log are process-wide and identical for both lanes; device log type names belong to the driver and share nothing across platforms. Standardise the first, discover the second.

solid answer

~40 s

Appium's logging splits along a seam. The **server's own log** is process configuration — `--log-level`, `--log`, `--log-timestamp` — chosen when `appium` starts, so it is genuinely identical for an Android session and an Apple one. The **device log** is session configuration in a per-driver vocabulary: `logcat` and `bugreport` from the Android drivers, `syslog`, `crashlog` and `safariConsole` from the XCUITest driver, with not one name in common. So you standardise the half that is portable — flags, file layout, timestamps, and one shared route, `POST /session/:sessionId/se/log` — and you refuse to standardise the half that is not. Instead you make the bucket name a per-platform mapping, resolved from `GET /session/:sessionId/se/log/types` or from `platformName`, and confined to one place.

go deeper

for a junior

Know that Appium's server log and a device log are configured in completely different ways, and that a bucket name you learned on one platform is not a name the other platform has.

for a middle

Be ready to explain which half of Appium logging is process-wide and which is per-session, and why the shared route hides the divergence in a request body rather than in the URL.

for a senior

Show that you keep the platform mapping in one component, capture inside the session scope, and can defend your verbosity and per-process file layout for a parallel run.

for a principal

Own the tradeoffs: one server or many, streaming on the lane that supports it against a single uniform pull, discovery per session against a cached map, and how much log volume the fleet's value justifies.

## The seam runs between the process and the session Every argument about "one logging config for the whole matrix" resolves once you see that Appium's log surface has two halves with different scopes and different owners. **Half one is process configuration.** The `appium` server's own stream is shaped by server flags — `--log-level` for verbosity, `--log` (short `-g`) for a file destination, `--log-timestamp` for per-line timestamps, alongside `--log-format`, `--log-filters`, `--log-no-colors`, `--debug-log-spacing`, `--long-stacktrace` and `--trace-dir` in the same schema. These are decided when the process starts. They apply to every session that process handles, so they cut across the platform divide, not along it. **Half two is session vocabulary.** A device log is fetched with `POST /session/:sessionId/se/log`, naming one type in the body, and discovered with `GET /session/:sessionId/se/log/types`. The route is shared; the names are not. The Android drivers publish `logcat` and `bugreport`; the XCUITest driver publishes `syslog`, `crashlog` and `safariConsole`. Nothing is common between the two lists. | | server's own log | device log | |---|---|---| | scope | the `appium` process | one session | | configured by | server flags at startup | a type name in the request body | | portable across platforms | yes, identically | no, no shared name | | where it belongs in your code | launch/infrastructure | a per-platform mapping | ## What you can standardise, and should These are the parts where one decision genuinely serves both lanes: - **Verbosity.** One `--log-level` choice for the fleet, so a failure on either platform yields comparable detail. - **Destination and layout.** `--log` per server process, with a naming scheme that says which process wrote which file. If you run a process per device, this gives you a per-lane file for free. - **Timestamps.** `--log-timestamp` everywhere, without exception. It is what makes a server line, a test report line and a device log entry line up at all; without it correlation degrades into reading by eye. - **The route.** `POST /session/:sessionId/se/log` and `GET /session/:sessionId/se/log/types` are the same on both lanes, under the Appium 3 `se/` spelling. Your transport code has no platform branch in it. - **The moment of capture.** Both routes are keyed by session id, so on both platforms the pull happens inside the session's own scope, never after it. ## What you must not standardise, and why pretending otherwise fails The temptation is to pick one bucket name and call it the suite's device log. It fails quietly and in a specific way: the URL resolves on both platforms, so nothing about the request shape warns you. The divergence lives entirely in the body, in a string. A helper written and proven on Android is structurally correct on an Apple session and semantically meaningless there. There is a second asymmetry worth naming honestly rather than papering over. The Android drivers declare `mobile: startLogsBroadcast` and `mobile: stopLogsBroadcast`, so an Android session can stream the log as it is produced; the measured XCUITest execute-method surface lists no counterpart. You can respond to that in one of two ways, and both are defensible: 1. **Take the asymmetry.** Stream on Android, pull on Apple platforms, and accept that your driver layer has two shapes. You get better evidence on the lane where the session may die with the app. 2. **Level down.** Pull on both, so one code path serves the whole matrix. Simpler to keep correct, weaker exactly when the crash also removes the session you needed to ask. The wrong answer is the third one: assume the broadcast exists on both because the name is a real Appium identifier. It is real and it belongs to a specific driver family. ## Where the platform branch should live One place. The suite expresses an intent — "give me the device log for this caving trip-log session" — and exactly one component turns that into a type name. That component either reads `platformName` for the session, or calls `GET /session/:sessionId/se/log/types` and picks from what the driver actually published. The second is stronger: it is a fact from the session rather than an assumption about it, and it degrades gracefully when a driver's list is not the one you expected. The payoff is that every other layer stays platform-blind. Test code never mentions `logcat`. Reporting never mentions `crashlog`. When a third driver enters the matrix, one mapping changes. ## The tradeoffs you actually own - **Verbosity against volume.** A high `--log-level` across a whole fleet produces a great deal of output whose value concentrates in the runs that failed. - **One server process or many.** Many gives you clean per-lane files and independent flags at the cost of orchestration; one gives you a single interleaved file that you separate by session id. - **Streaming against uniformity**, as above — better Android evidence versus one code path. - **Discovery against a hardcoded map.** A `se/log/types` call per session costs a round trip and buys correctness that a table in your repo cannot guarantee. None of these has one right answer, and that is the point: the portable half is a decision you make once, and the divergent half is a mapping you own deliberately rather than discover by outage.

  • Would you run one Appium server for a mixed fleet or one per device, purely on logging grounds?
    One per device, usually. `--log` names a file per process, so a process per device gives a per-lane log without any post-processing, and each lane can carry its own verbosity. A single shared server is defensible when the fleet is small and you are content to separate the interleaved stream by session id, but that is work you do on every triage rather than once at launch.
  • What is the argument against calling se/log/types on every session?
    It is a round trip per session, and on a large parallel fleet those add up. The counter-argument is that the alternative is a hardcoded map of another project's vocabulary, which is correct only until a driver changes it. A reasonable middle course is to discover once per driver-and-platform combination in a run and cache it for that run.

saying these in an interview costs you the question

  • Wants a single device log type name for the whole matrix
  • Assumes mobile: startLogsBroadcast works on Apple sessions too
  • Scatters platform-specific bucket names through test code
  • Thinks server flags can change what a device log contains
  • Runs the fleet without --log-timestamp and correlates by eye
  • Points two server processes at the same --log file