Hi everyone,
Today, I would like to announce ContextTracking.jl, a package that helps you keep track of contextual information during program execution.
A quick example
Suppose that you have 4 functions: A calls B, B calls C, and C calls D. Normally, if you have gathered some data in A and want to access it in D, you would have to pass the data downstream via function arguments. With ContextTracking, you just access it directly in D.
Unlike global variables, context information is kept only during the lifetime of the execution call chain. All that is maintained in a stack structure. When the function returns, the data is cleaned up and removed.
How is it useful?
Just taking a use case description from the project’s README:
Suppose that we are processing a web request. We may want to create a correlation id to keep track of the request and include the request id whenever we write anything to the log file during any part of the processing of that request.
It may seems somewhat redundant to log the same data multiple times but it is invaluable in debugging production problems. Imagine that two users are hitting the same web service at the same time. If we look at the log file, everything could be interleaving and it would be quite confusing without the context.
As context data is stored in a stack structure, you naturally gain more “knowledge” when going deeper into the execution stack. Then, you naturally “forget” about those details when the execution stack unwinds. With this design, you can just memoize the most valuable knowledge needed in the log file.
Demo
using ContextTracking
@ctx function foo()
@memo x = 1
bar()
end
@ctx function bar()
c = context()
@info "context data" c.data
end
Result:
julia> foo()
┌ Info: context data
│ c.data =
│ Dict{Any,Any} with 2 entries:
│ :_ContextPath_ => [:foo, :bar]
â”” :x => 1