lib/timber/current_context.rb in timber-1.0.3 vs lib/timber/current_context.rb in timber-1.0.4

- old
+ new

@@ -2,42 +2,103 @@ module Timber # Holds the current context in a thread safe memory storage. This context is # appended to every log line. Think of context as join data between your log lines, # allowing you to relate them and filter them appropriately. + # + # @note Because context is appended to every log line, it is recommended that you limit this + # to only neccessary data needed to relate your log lines. class CurrentContext include Singleton THREAD_NAMESPACE = :_timber_current_context.freeze class << self - # Convenience method for {#with}. - # - # @example Adding a context - # custom_context = Timber::Contexts::Custom.new(type: :keyspace, data: %{my: "data"}) - # Timber::CurrentContext.with(custom_context) do - # # ... anything logged here will have the context ... - # end + # Convenience method for {#with}. See {#with} for full details and examples. def with(*args, &block) instance.with(*args, &block) end + + # Convenience method for {#add}. See {#add} for full details and examples. + def add(*args) + instance.add(*args) + end + + # Convenience method for {#remove}. See {#remove} for full details and examples. + def remove(*args) + instance.remove(*args) + end + + def hash(*args) + instance.hash(*args) + end end - # Adds a context to the current stack. - def with(data) - key = data.keyspace - hash[key] = data + # Adds a context and then removes it when the block is finished executing. + # + # @note Because context is included with every log line, it is recommended that you limit this + # to only neccessary data. + # + # @example Adding a custom context + # custom_context = Timber::Contexts::Custom.new(type: :organization, data: %{id: 1, name: "Timber"}) + # Timber::CurrentContext.with(custom_context) do + # # ... anything logged here will include the context ... + # end + # # Be sure to checkout Timber::Contexts! These are officially supported and many of these + # # will be automatically included via Timber::Probes + # + # @example Adding multiple contexts + # Timber::CurrentContext.with(context1, context2) { ... } + def with(*contexts) + add(*contexts) yield ensure - hash.delete(key) + contexts.each do |context| + if context.keyspace == :custom + # Custom contexts are merged and should be removed the same + hash[context.keyspace].delete(context.type) + else + remove(context) + end + end end - def snapshot - hash.clone + # Adds contexts but does not remove them. See {#with} for automatic maintenance and {#remove} + # to remove them yourself. + # + # @note Because context is included with every log line, it is recommended that you limit this + # to only neccessary data. + def add(*contexts) + contexts.each do |context| + key = context.keyspace + json = context.as_json # Convert to json now so that we aren't doing it for every line + if key == :custom + # Custom contexts are merged into the space + hash[key] ||= {} + hash[key].merge(json) + else + hash[key] = json + end + end end - private - def hash - Thread.current[THREAD_NAMESPACE] ||= {} + # Removes a context. This must be a {Timber::Context} type. See {Timber::Contexts} for a list. + # If you wish to remove by key, or some other way, use {#hash} and modify the hash accordingly. + def remove(*contexts) + contexts.each do |context| + hash.delete(context.keyspace) end + end + + # The internal hash that is maintained. It is recommended that you use {#with} and {#add} + # for hash maintenance. + def hash + Thread.current[THREAD_NAMESPACE] ||= {} + end + + # Snapshots the current context so that you get a moment in time representation of the context, + # since the context can change as execution proceeds. + def snapshot + hash.clone + end end end \ No newline at end of file