Skip to content
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,95 @@ The next time this code is run, it simply
loads and displays the saved HTML representation,
which can be much faster!

## Example: Caching printed output and logs

Sometimes it's useful to also save things printed to stdout/stderr or logged during a computation.
This can be accomplished by capturing the output using [IOCapture.jl](https://github.com/JuliaDocs/IOCapture.jl) and `Logging.SimpleLogger`.

First, install IOCapture.jl if you haven't already:
```julia
using Pkg; Pkg.add("IOCapture")
```

Then use it to capture output:

```julia
using CacheVariables, Logging, IOCapture

cache("simulation-with-output.bson") do
# Create an IOBuffer to capture logs
logs_io = IOBuffer()

# Use IOCapture to capture stdout/stderr and SimpleLogger for logs
captured = IOCapture.capture() do
with_logger(SimpleLogger(logs_io)) do
println("Starting simulation...")
@info "Running expensive computation"

# Your expensive computation here
output = sum(1:1000)

println("Computation finished with result: ", output)
@info "Simulation complete" result=output

return output
end
end

# Extract captured logs from the IOBuffer
logs_content = String(take!(logs_io))

# Return result along with captured output
return (; result=captured.value, stdout=captured.output, logs=logs_content)
end
```

The first time this runs, it executes the computation and captures all printed output and log messages,
saving everything to the cache file.
Subsequent runs simply load the cached result along with the captured output and logs!

This is particularly useful for:
- Long-running simulations that produce diagnostic output
- Debugging cached computations by reviewing what was printed
- Preserving a complete record of what happened during a computation

**Alternative approaches:**

If you prefer not to use IOCapture.jl, you can use a file-based approach with `redirect_stdio`:

```julia
using CacheVariables, Logging

cache("simulation-with-output.bson") do
mktempdir() do tmpdir
stdout_file = joinpath(tmpdir, "stdout.txt")
logs_file = joinpath(tmpdir, "logs.txt")

result = open(stdout_file, "w") do stdout_io
open(logs_file, "w") do logs_io
redirect_stdio(stdout=stdout_io) do
with_logger(SimpleLogger(logs_io)) do
println("Starting simulation...")
@info "Running expensive computation"
output = sum(1:1000)
println("Computation finished with result: ", output)
@info "Simulation complete" result=output
return output
end
end
end
end

stdout_content = read(stdout_file, String)
logs_content = read(logs_file, String)

return (; result=result, stdout=stdout_content, logs=logs_content)
end
end
```

This file-based approach is useful when dealing with very large amounts of output or when you need more control over the capturing process.

## Related packages

- [Memoization.jl](https://github.com/marius311/Memoization.jl)