Class: Labkit::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/labkit/context.rb

Overview

A context can be used to provide structured information on what resources GitLab is working on within a service. The currently supported keys are defined in the KNOWN_KEYS constant.

Values can be provided by passing a hash. If one of the values is a Proc the proc will only be called when the value is actually needed.

Multiple contexts can be nested, the nested context will inherit the values from the closest outer one. All contexts will have the same correlation id.

Usage:

Labkit::Context.with_context(user: 'username', root_namespace: -> { get_root_namespace } do |context|
  logger.info(context.to_h)
end

Constant Summary collapse

LOG_KEY =
"meta"
CORRELATION_ID_KEY =
"correlation_id"
RAW_KEYS =
[CORRELATION_ID_KEY].freeze
HEADER_PREFIX =
"X-Gitlab-"
KNOWN_KEYS =
%w[user project root_namespace subscription_plan caller_id
remote_ip related_class feature_category client_id].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(values = {}) ⇒ Context

Returns a new instance of Context.



88
89
90
91
92
# File 'lib/labkit/context.rb', line 88

def initialize(values = {})
  @data = {}

  assign_attributes(values)
end

Class Method Details

.correlation_idObject



57
58
59
# File 'lib/labkit/context.rb', line 57

def correlation_id
  contexts.last&.correlation_id
end

.currentObject



61
62
63
# File 'lib/labkit/context.rb', line 61

def current
  contexts.last
end

.header_name(name) ⇒ Object



77
78
79
# File 'lib/labkit/context.rb', line 77

def header_name(name)
  HEADER_PREFIX + log_key(name).titlecase(keep_id_suffix: true).gsub(/\W/, "-")
end

.known_log_keysObject



73
74
75
# File 'lib/labkit/context.rb', line 73

def known_log_keys
  @known_log_keys ||= (KNOWN_KEYS.map(&method(:log_key)) + RAW_KEYS).freeze
end

.log_key(key) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/labkit/context.rb', line 65

def log_key(key)
  key = key.to_s
  return key if RAW_KEYS.include?(key)
  return key if key.starts_with?("#{LOG_KEY}.")

  "#{LOG_KEY}.#{key}"
end

.pop(context) ⇒ Object



53
54
55
# File 'lib/labkit/context.rb', line 53

def pop(context)
  contexts.pop while contexts.include?(context)
end

.push(new_attributes = {}) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/labkit/context.rb', line 45

def push(new_attributes = {})
  new_context = current&.merge(new_attributes) || new(new_attributes)

  contexts.push(new_context)

  new_context
end

.with_context(attributes = {}) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/labkit/context.rb', line 35

def with_context(attributes = {})
  context = push(attributes)

  begin
    yield(context)
  ensure
    pop(context)
  end
end

Instance Method Details

#correlation_idObject



105
106
107
# File 'lib/labkit/context.rb', line 105

def correlation_id
  data[CORRELATION_ID_KEY]
end

#get_attribute(attribute) ⇒ Object



115
116
117
118
119
# File 'lib/labkit/context.rb', line 115

def get_attribute(attribute)
  raw = call_or_value(data[log_key(attribute)])

  call_or_value(raw)
end

#merge(new_attributes) ⇒ Object



94
95
96
97
98
99
# File 'lib/labkit/context.rb', line 94

def merge(new_attributes)
  new_context = self.class.new(data.dup)
  new_context.assign_attributes(new_attributes)

  new_context
end

#to_hObject



101
102
103
# File 'lib/labkit/context.rb', line 101

def to_h
  expand_data
end

#to_headersObject



109
110
111
112
113
# File 'lib/labkit/context.rb', line 109

def to_headers
  to_h.except(CORRELATION_ID_KEY).transform_keys do |key|
    self.class.header_name(key)
  end
end