SEZ9 opened a new pull request, #12299:
URL: https://github.com/apache/seatunnel/pull/12299

   ### Purpose of this pull request
   
   Closes #12295.
   
   The REST log-content endpoints read the whole file into a `String` before 
writing the response:
   
   ```java
   // LogBaseServlet#prepareLogResponse
   String logContent = FileUtils.readFileToStr(new 
File(canonicalFilePath).toPath());
   write(resp, logContent);
   ```
   
   ```java
   // FileUtils#readFileToStr
   byte[] bytes = Files.readAllBytes(path);
   return new String(bytes);
   ```
   
   That materialises the file twice on the heap, once as a byte array and once 
as a string, with no upper bound. A streaming job's log file grows without 
limit, so a single `GET /logs/<name>` on a job that has been running for weeks 
was enough to push the node into a long GC pause or an `OutOfMemoryError` — 
taking down the engine node rather than just failing the request. 
`RestHttpGetCommandProcessor` carries an equivalent copy for REST v1 and had 
the same problem.
   
   This adds `seatunnel.engine.http.log-response-max-size-mb` and reads at most 
that much from the **end** of the file, the tail being the part that matters 
when diagnosing a failure.
   
   The existing path-traversal guard in `prepareLogResponse` is untouched; this 
is purely about response size.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes.
   
   **New option `seatunnel.engine.http.log-response-max-size-mb`, default 
`64`.** A log file larger than the limit is truncated to its last 64 MB instead 
of being returned whole. Setting the option to `0` or a negative value restores 
the previous unlimited behaviour, matching how `upload-max-file-size-mb` treats 
non-positive values.
   
   On the default: 64 MB of text is already far past what a browser or a human 
consumes, and the transient cost of serving it is roughly 64 MB for the byte 
array plus up to 128 MB for the string. Picking a much larger default would 
keep a single request able to exhaust a typical node heap, which is the thing 
being fixed. Anyone who genuinely needs whole multi-gigabyte files can set `0` 
and accept the heap cost explicitly.
   
   Truncation is aligned to the first line break after the cut point, so a 
response never begins mid-line, and never begins in the middle of a multi-byte 
UTF-8 character — slicing at an arbitrary byte offset would otherwise make a 
CJK log start with a replacement character. Where a single line is longer than 
the whole limit there is no line boundary to align to, so only the leading 
UTF-8 continuation bytes are dropped.
   
   Content in the new path is decoded as UTF-8 explicitly, whereas 
`readFileToStr` uses the platform default charset. Reasoning about character 
boundaries is only meaningful against a known encoding, and log4j2 writes 
UTF-8. I deliberately did not change `readFileToStr` itself — that would touch 
every caller and belongs in its own change.
   
   Docs updated in `docs/en/engines/zeta/rest-api-v2.md` and 
`docs/zh/engines/zeta/rest-api-v2.md`: the code-defaults list, the config 
example, and a note under both the all-node and single-node log endpoints.
   
   ### How was this patch tested?
   
   Unit tests in `FileUtilsTest`, covering `readFileTailToStr`:
   
   - a file below the limit, and a file exactly at the limit, are returned 
whole;
   - a non-positive limit means unlimited;
   - an empty file returns `""`;
   - above the limit the result is a suffix of the file, smaller than the 
limit, starting at a line boundary and reaching the end of the file;
   - **UTF-8 safety**: a file of three-byte CJK characters is read with every 
limit from 100 to 400 bytes, so some cut points necessarily land inside a 
character. Each result is asserted to contain no `U+FFFD`, to be a suffix of 
the file, and to start at a line boundary;
   - a single line longer than the limit, where there is no boundary to align 
to, still decodes without a replacement character.
   
   The new config option is also asserted in `YamlSeaTunnelConfigParserTest` 
against a non-default value in the test `seatunnel.yaml`. That is not ceremony: 
an `http` option without a matching branch in 
`YamlSeaTunnelDomConfigProcessor.parseHttpConfig` is silently dropped with an 
`"Unrecognized element"` warning, so without that assertion the option could 
ship inert and look fine.
   
   I do not have a JDK/Maven in my working environment, so I have not run the 
suite locally — CI is the first execution of these changes.
   
   One thing I left as-is for reviewers to weigh in on: `LogBaseServlet` and 
`RestHttpGetCommandProcessor` each resolve the limit separately, because the v1 
and v2 code paths sit in different class hierarchies and already duplicate the 
whole of `prepareLogResponse`. Unifying them is a larger refactor than this fix 
warrants, but I am happy to do it here if you would rather.
   
   ### Check list
   
   * [x] If any new Jar binary package adding in your PR, please add License 
Notice according
     [New License 
Guide](https://github.com/apache/seatunnel/blob/dev/docs/en/developer/new-license.md)
   * [x] If necessary, please update the documentation to describe the new 
feature. https://github.com/apache/seatunnel/tree/dev/docs
   * [x] If necessary, please update `incompatible-changes.md` to describe the 
incompatibility caused by this PR.
   * [x] If you are contributing the connector code, please check that the 
following files are updated:
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to