A JMeter CSV results file kept for six months has no header row and non-numeric timestamps. How do you read it?
answer
- Two save properties explain both symptoms
- Field order is fixed; the set varies
- Count fields, then compare to the default
- Formatted dates carry no zone offset
- Delimiter and timestamp come from properties
basics
~20 sBoth symptoms come from save properties on the injector that wrote it: print_field_names was false, and timestamp_format was a date pattern instead of the default ms. Rebuild the column list from JMeter's fixed field order, then confirm the writing machine's time zone.
solid answer
~40 sTwo properties explain it. `jmeter.save.saveservice.print_field_names` was set to `false`, so no header line was written; and `jmeter.save.saveservice.timestamp_format` was set to a date pattern rather than its default `ms`, so the first column holds formatted dates instead of epoch milliseconds. Recovery leans on the fact that the **column order is fixed in JMeter's writer** — only the set of columns varies. Count the fields on a line, match them against the documented order, and the assignment usually falls out; the optional fields (`Filename`, `Encoding`, `SampleCount`/`ErrorCount`, `Hostname`) are the ones to test for. For the dates, note that JMeter formats them in the writing JVM's default time zone and writes no offset unless the pattern carried one, so you must establish which machine wrote the file before the times mean anything.
code
properties · 4 lines# on the injector that wrote the file - NOT stored inside the .jmx
jmeter.save.saveservice.print_field_names=false
jmeter.save.saveservice.timestamp_format=yyyy/MM/dd HH:mm:ss.SSS
jmeter.save.saveservice.default_delimiter=|go deeper
Know that a results file normally starts with a header line naming its columns, and that the timestamp is normally milliseconds since 1970.
Name print_field_names and timestamp_format, give their defaults, and explain that the column order is fixed while the set of columns present is configurable.
Recover a file nobody documented: count fields against the fixed order, identify which optional columns were enabled, and refuse to read formatted timestamps until the writing machine's time zone is established.
Treat the properties that shaped the file as part of the evidence. Decide what a run archives beyond the results file itself, so a result stays legible after the people and the injectors have moved on.
This is the failure mode that makes a results file useless as evidence: the numbers are all there, and nobody can say what they are. It is worth working through, because every step of the recovery is also the argument for how to write the file in the first place. ## Symptom one: no header line `jmeter.save.saveservice.print_field_names` defaults to `true`, and when it is true JMeter writes the column names as the first line of a CSV results file. A file with no header was written by a JVM where someone set it to `false`. The recovery works because the **order** of the columns is fixed in the writer, independent of the property file: switching a field off removes its column and leaves the rest in place. The full order is: 1. `timeStamp`, `elapsed`, `label`, `responseCode`, `responseMessage`, `threadName`, `dataType`, `success`, `failureMessage` 2. `bytes`, `sentBytes`, `grpThreads`, `allThreads`, `URL`, `Filename` 3. `Latency`, `Encoding`, `SampleCount`, `ErrorCount`, `Hostname`, `IdleTime`, `Connect` 4. any names listed in the `sample_variables` property, appended last The default set is seventeen fields — everything above except `Filename`, `Encoding`, `SampleCount`, `ErrorCount` and `Hostname`, which are off by default. So counting fields on a line and comparing to seventeen tells you immediately whether anything unusual was enabled, and the shape of the values (booleans, URLs, host names) settles the rest. ## Symptom two: dates instead of milliseconds `jmeter.save.saveservice.timestamp_format` takes three kinds of value: | Value | Effect on the CSV | |---|---| | `ms` (the default) | `timeStamp` is epoch milliseconds | | a `SimpleDateFormat` pattern | `timeStamp` is that pattern, rendered in the writing JVM's default time zone | | `none` | the `timeStamp` column is not written at all | The trap is the middle row. JMeter renders the instant in the **default time zone of the machine that ran the test**, and unless the pattern itself contains a zone or offset field, that context is nowhere in the file. Two injectors in two regions produce files that look identical and are hours apart. Epoch milliseconds have no such ambiguity, which is why the default is the right default. There is a reading-side detail worth knowing: when JMeter itself loads a CSV results file configured for `ms` and a value does not parse as a long, it tries a short list of formats — `yyyy/MM/dd HH:mm:ss.SSS`, `yyyy/MM/dd HH:mm:ss`, `yyyy-MM-dd HH:mm:ss.SSS`, `yyyy-MM-dd HH:mm:ss`, and finally the legacy `MM/dd/yy HH:mm:ss`. If the file was written with one of those patterns, JMeter can still open it. ## Why the .jmx did not save you A listener stores its per-field save flags inside the plan, so those travel with the `.jmx`. Two things deliberately do not: the field delimiter and whether the timestamp is printed as milliseconds. Both are read from the property files of the JVM that runs the test, every time. Archiving the plan is therefore not enough — the `jmeter.properties` and `user.properties` in force are part of the evidence, and so is the injector's time zone. ## Making the next file readable - keep `print_field_names=true` so the file describes itself; - keep `timestamp_format=ms`, or use a pattern that carries an explicit zone; - keep the default comma delimiter unless a field genuinely forces otherwise; - store the properties file beside the results file, not just the plan. One more failure worth recognising: if `timestamp_format` is set to a pattern JMeter cannot compile, it logs an error and ends up with no formatter. The header still lists `timeStamp`, but the writer emits nothing for that field, so every data row is one field short and every column after it reads shifted by one. A file whose `elapsed` column is full of sampler names has almost certainly hit exactly this.
- Does archiving the .jmx alongside the JTL tell you how the file was written?Only partly. A listener's per-field save flags are stored in the plan, but the delimiter and the timestamp-versus-milliseconds choice deliberately are not — they are read from the running JVM's property files each time. Archive jmeter.properties and user.properties too.
- What does jmeter.save.saveservice.timestamp_format=none do?It removes the timeStamp column from the file entirely, rather than changing its rendering. Rows start at elapsed and the header, if written, omits timeStamp as well. It is rarely what anyone wants in a file kept as evidence.
- Every row of a kept JMeter CSV has one field fewer than the header. What causes that?A timestamp_format value JMeter could not compile as a date pattern. It logs the bad pattern and holds no formatter, so the writer emits nothing for the timestamp field while the header still names it, shifting every subsequent column by one.
saying these in an interview costs you the question
- Assumes the column order can vary between files
- Reads formatted timestamps without asking which time zone
- Says the .jmx records the delimiter and timestamp format
- Treats a missing header as file corruption
- Guesses column meanings from position without counting fields