gitlab-labkit 0.10.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2476531528be243ed0069feffe3bbfbc7d557556455616e7d4216aa686422409
4
- data.tar.gz: 43223820267f18725601573595ba607178788178b1922835becaf7c72d593b2f
3
+ metadata.gz: 54ad7f3ed011ed85b6f0c090f05cd47a4bf7c738fabd2a165bad85b6e4d288c0
4
+ data.tar.gz: c833a07fa745fe8286b9c000879de8b0f338c0d24b722e71dc5044c60dcc3b79
5
5
  SHA512:
6
- metadata.gz: 712fd95e6a754409e83a8b5ee690c1843b233794a33a7461dea2fdc84c49eb8e873c7298ee15087302c32b60faeca83fd3592a80e471640a3c80710fa094e54e
7
- data.tar.gz: e6d4d048caa06702bd47326574d105f32d9d5e7c27d3c619ac529e4cb35f671a7cfca92e1d9b6460a1b6080c90bc05306f2df17381ca6e104ad30a5171a22bb8
6
+ metadata.gz: 5c724e7322119314f35831c726900220842e2f473a48d81241a94cc2eb4f34da39bb38c843ba72b724a1b5d0dff5e1b115cec704468d49797d4c681c309cf7ba
7
+ data.tar.gz: 91e870d9af690c2b5f6ce7659954616880ee3313f710b49c89505cbe915c4606ef3d1032d905cbfd1be4e547d98c846baa6fed052836833e71dc7a59444c0727
@@ -21,7 +21,8 @@ module Labkit
21
21
  LOG_KEY = "meta"
22
22
  CORRELATION_ID_KEY = "correlation_id"
23
23
  RAW_KEYS = [CORRELATION_ID_KEY].freeze
24
- KNOWN_KEYS = %w[user project root_namespace subscription_plan caller_id].freeze
24
+ KNOWN_KEYS = %w[user project root_namespace subscription_plan caller_id
25
+ related_class feature_category].freeze
25
26
 
26
27
  class << self
27
28
  def with_context(attributes = {})
@@ -7,6 +7,16 @@ module Labkit
7
7
  # It is not part of the public API
8
8
  module GRPCCommon
9
9
  CORRELATION_METADATA_KEY = "x-gitlab-correlation-id"
10
+
11
+ def rpc_split(method)
12
+ owner = method.owner
13
+ method_name, = owner.rpc_descs.find do |k, _|
14
+ ::GRPC::GenericService.underscore(k.to_s) == method.name.to_s
15
+ end
16
+ method_name ||= "(unknown)"
17
+
18
+ [owner.service_name, method_name]
19
+ end
10
20
  end
11
21
  end
12
22
  end
@@ -4,6 +4,7 @@ module Labkit
4
4
  # Logging provides functionality for logging, such as
5
5
  # sanitization
6
6
  module Logging
7
+ autoload :GRPC, "labkit/logging/grpc"
7
8
  autoload :Sanitizer, "labkit/logging/sanitizer"
8
9
  end
9
10
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ module Logging
5
+ module GRPC
6
+ autoload :ServerInterceptor, "labkit/logging/grpc/server_interceptor"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grpc"
4
+ require "json"
5
+
6
+ module Labkit
7
+ module Logging
8
+ module GRPC
9
+ class ServerInterceptor < ::GRPC::ServerInterceptor
10
+ include Labkit::Correlation::GRPC::GRPCCommon
11
+
12
+ CODE_STRINGS = {
13
+ ::GRPC::Core::StatusCodes::OK => "OK",
14
+ ::GRPC::Core::StatusCodes::CANCELLED => "Canceled",
15
+ ::GRPC::Core::StatusCodes::UNKNOWN => "Unknown",
16
+ ::GRPC::Core::StatusCodes::INVALID_ARGUMENT => "InvalidArgument",
17
+ ::GRPC::Core::StatusCodes::DEADLINE_EXCEEDED => "DeadlineExceeded",
18
+ ::GRPC::Core::StatusCodes::NOT_FOUND => "NotFound",
19
+ ::GRPC::Core::StatusCodes::ALREADY_EXISTS => "AlreadyExists",
20
+ ::GRPC::Core::StatusCodes::PERMISSION_DENIED => "PermissionDenied",
21
+ ::GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED => "ResourceExhausted",
22
+ ::GRPC::Core::StatusCodes::FAILED_PRECONDITION => "FailedPrecondition",
23
+ ::GRPC::Core::StatusCodes::ABORTED => "Aborted",
24
+ ::GRPC::Core::StatusCodes::OUT_OF_RANGE => "OutOfRange",
25
+ ::GRPC::Core::StatusCodes::UNIMPLEMENTED => "Unimplemented",
26
+ ::GRPC::Core::StatusCodes::INTERNAL => "Internal",
27
+ ::GRPC::Core::StatusCodes::UNAVAILABLE => "Unavailable",
28
+ ::GRPC::Core::StatusCodes::DATA_LOSS => "DataLoss",
29
+ ::GRPC::Core::StatusCodes::UNAUTHENTICATED => "Unauthenticated",
30
+ }.freeze
31
+
32
+ def initialize(log_file, default_tags)
33
+ @log_file = log_file
34
+ @log_file.sync = true
35
+ @default_tags = default_tags
36
+
37
+ super()
38
+ end
39
+
40
+ def request_response(request: nil, call: nil, method: nil)
41
+ log_request(method, call) { yield }
42
+ end
43
+
44
+ def server_streamer(request: nil, call: nil, method: nil)
45
+ log_request(method, call) { yield }
46
+ end
47
+
48
+ def client_streamer(call: nil, method: nil)
49
+ log_request(method, call) { yield }
50
+ end
51
+
52
+ def bidi_streamer(requests: nil, call: nil, method: nil)
53
+ log_request(method, call) { yield }
54
+ end
55
+
56
+ private
57
+
58
+ def log_request(method, call)
59
+ start = Time.now
60
+ code = ::GRPC::Core::StatusCodes::OK
61
+
62
+ yield
63
+ rescue StandardError => ex
64
+ code = ex.is_a?(::GRPC::BadStatus) ? ex.code : ::GRPC::Core::StatusCodes::UNKNOWN
65
+
66
+ raise
67
+ ensure
68
+ service_name, method_name = rpc_split(method)
69
+ message = @default_tags.merge(
70
+ 'grpc.time_ms': ((Time.now - start) * 1000.0).truncate(3),
71
+ 'grpc.code': CODE_STRINGS.fetch(code, code.to_s),
72
+ 'grpc.method': method_name,
73
+ 'grpc.service': service_name,
74
+ pid: Process.pid,
75
+ correlation_id: Labkit::Correlation::CorrelationId.current_id.to_s,
76
+ time: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ"),
77
+ )
78
+
79
+ @log_file.puts(JSON.dump(message))
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -28,6 +28,10 @@ module Labkit
28
28
  ENV["GITLAB_TRACING_URL"]
29
29
  end
30
30
 
31
+ def self.stacktrace_operations
32
+ @stacktrace_operations ||= Set.new(ENV["GITLAB_TRACING_INCLUDE_STACKTRACE"].to_s.split(",").map(&:strip))
33
+ end
34
+
31
35
  def self.tracing_url_enabled?
32
36
  enabled? && tracing_url_template.present?
33
37
  end
@@ -14,6 +14,8 @@ module Labkit
14
14
  # for instrumenting GRPC calls with distributed tracing
15
15
  # in a GRPC Ruby server
16
16
  class ServerInterceptor < ::GRPC::ServerInterceptor
17
+ include Labkit::Correlation::GRPC::GRPCCommon
18
+
17
19
  def request_response(request: nil, call: nil, method: nil)
18
20
  wrap_with_tracing(call, method, "unary") do
19
21
  yield
@@ -40,16 +42,9 @@ module Labkit
40
42
 
41
43
  private
42
44
 
43
- def route_from_method(method)
44
- service_class = method.owner
45
- rpc_method = method.name.to_s.split("_").map(&:capitalize).join("")
46
-
47
- "/#{service_class.service_name}/#{rpc_method}"
48
- end
49
-
50
45
  def wrap_with_tracing(call, method, grpc_type)
51
46
  context = TracingUtils.tracer.extract(OpenTracing::FORMAT_TEXT_MAP, call.metadata)
52
- method_name = route_from_method(method)
47
+ method_name = "/#{rpc_split(method).join("/")}"
53
48
  tags = {
54
49
  "component" => "grpc",
55
50
  "span.kind" => "server",
@@ -17,6 +17,8 @@ module Labkit
17
17
  scope = scope_stack.pop
18
18
  span = scope.span
19
19
 
20
+ Labkit::Tracing::TracingUtils.log_common_fields_on_span(span, span_name(payload))
21
+
20
22
  exception = payload[:exception]
21
23
  Labkit::Tracing::TracingUtils.log_exception_on_span(span, exception) if exception
22
24
 
@@ -8,7 +8,7 @@ module Labkit
8
8
  # RedisInterceptorHelper is a helper for the RedisInterceptor. This is not a public API
9
9
  class RedisInterceptorHelper
10
10
  # For optimization, compile this once
11
- MASK_REDIS_RE = /^([\w-]+(?:\W+[\w-]+(?:\W+[\w-]+)?)?)(.?)/.freeze
11
+ MASK_REDIS_RE = /^([\w{}-]+(?:\W+[\w{}-]+(?:\W+[\w{}-]+)?)?)(.?)/.freeze
12
12
 
13
13
  def self.call_with_tracing(command, client)
14
14
  Labkit::Tracing::TracingUtils.with_tracing(operation_name: "redis.call", tags: tags_from_command(command, client)) do |_span|
@@ -99,6 +99,7 @@ module Labkit
99
99
  return "" if argument.empty?
100
100
 
101
101
  matches = argument.match(MASK_REDIS_RE)
102
+
102
103
  matches[2].empty? ? matches[0] : matches[0] + "*****"
103
104
  end
104
105
  private_class_method :mask_redis_arg
@@ -12,9 +12,7 @@ module Labkit
12
12
  scope = tracer.start_active_span(operation_name, child_of: child_of, tags: tags)
13
13
  span = scope.span
14
14
 
15
- # Add correlation details to the span if we have them
16
- correlation_id = Labkit::Correlation::CorrelationId.current_id
17
- span.set_tag("correlation_id", correlation_id) if correlation_id
15
+ log_common_fields_on_span(span, operation_name)
18
16
 
19
17
  begin
20
18
  yield span
@@ -35,11 +33,19 @@ module Labkit
35
33
  def self.postnotify_span(operation_name, start_time, end_time, tags: nil, child_of: nil, exception: nil)
36
34
  span = OpenTracing.start_span(operation_name, start_time: start_time, tags: tags, child_of: child_of)
37
35
 
36
+ log_common_fields_on_span(span, operation_name)
38
37
  log_exception_on_span(span, exception) if exception
39
38
 
40
39
  span.finish(end_time: end_time)
41
40
  end
42
41
 
42
+ # Add common fields to a span
43
+ def self.log_common_fields_on_span(span, operation_name)
44
+ correlation_id = Labkit::Correlation::CorrelationId.current_id
45
+ span.set_tag("correlation_id", correlation_id) if correlation_id
46
+ span.log_kv(stack: caller.join('\n')) if include_stacktrace?(operation_name)
47
+ end
48
+
43
49
  # Add exception logging to a span
44
50
  def self.log_exception_on_span(span, exception)
45
51
  span.set_tag("error", true)
@@ -60,6 +66,14 @@ module Labkit
60
66
  { :"event" => "error", :"error.kind" => exception.class.to_s, :"error.object" => Labkit::Logging::Sanitizer.sanitize_field(exception.to_s) }
61
67
  end
62
68
  end
69
+
70
+ def self.include_stacktrace?(operation_name)
71
+ @include_stacktrace ||= Hash.new do |result, name|
72
+ result[name] = Tracing.stacktrace_operations.any? { |stacktrace_operation| name.starts_with?(stacktrace_operation) }
73
+ end
74
+
75
+ @include_stacktrace[operation_name]
76
+ end
63
77
  end
64
78
  end
65
79
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-labkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Newdigate
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-05 00:00:00.000000000 Z
11
+ date: 2020-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -279,6 +279,8 @@ files:
279
279
  - lib/labkit/correlation/grpc/grpc_common.rb
280
280
  - lib/labkit/correlation/grpc/server_interceptor.rb
281
281
  - lib/labkit/logging.rb
282
+ - lib/labkit/logging/grpc.rb
283
+ - lib/labkit/logging/grpc/server_interceptor.rb
282
284
  - lib/labkit/logging/sanitizer.rb
283
285
  - lib/labkit/middleware.rb
284
286
  - lib/labkit/middleware/rack.rb