The Crystal Programming Language Forum

Kemal - how to show elapsed time

In my Kemal based application I wanted to show the elapsed time.
So in the layout.ecr I added <%= Time.monotonic - start %> but I did not know where to set start.

If I set in the body of the main .cr file then it will be set at startup time.
If I set it in before_all then it will be scoped and won’t be available in the template.

Is there some global variable where it could be stored and then retrieved in the template?

I’m not sure what the actual solution is, but Kemal does this in a Handler kemal/log_handler.cr at master · kemalcr/kemal · GitHub Maybe that can get you pointed in the right direction?

Oh I just found a solution.

The Crystal code:

global = {
  "start" => Time.monotonic,
}

before_all do
  global["start"] = Time.monotonic
end

The template:

Elapsed time <%= (Time.monotonic - global["start"]).total_milliseconds %> ms

You would be better off using a module with class vars. Pretty sure the only reason this works is because of how Kemal works. I.e. it pollutes the top level namespace making this local var appear as if it’s global.

And this is prone to error with concurrent requests. With Kemal it’s probably best to attach the start time to the env context.

1 Like

Do you mean to have a class instead of that “global” variable?

class Global
  class_property start = Time.monotonic
end

before_all do
  Global.start = Time.monotonic
end

and

Elapsed time <%= (Time.monotonic - Global.start).total_milliseconds %> ms

Is this better?

My first attempt was to attach it to the context (aka. env), but could not find a way.

That’s the more Crystal way to handle “global” variables given such a thing doesn’t actually exist. However as @straight-shoota pointed out, this does not bode well with concurrent requests since the value would be mutated/bleed between requests.

Prob just monkey patch it in:

class HTTP::Server::Context
  getter start_time : Time = Time.monotonic
end