kubetailrb 0.2.0 → 0.3.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: 427b49a8499da9f1c69481130560ba2b783dc122b1a89146e4b2e6ce2f516ec9
4
- data.tar.gz: 6be87b2d3529725ef21c2acaee397ddf1989dec3e91bd98f9b99494c6531b9e2
3
+ metadata.gz: '0916dd6a8baf85b2f7b4771e9d0623fdbe1ff22ca0ea4111cc54ba1fcfab7fd4'
4
+ data.tar.gz: 051cc8d7bae42f86ce12b2ac43a567674d187170c73f5079aee14f66cb91a44b
5
5
  SHA512:
6
- metadata.gz: a63a5917935cda345eab9b35f918efdd84778bc58ababf1ede52425cbb71760ac40738cf24ae11596b0c71b373c7aee00b25ec4fc343d0b58deb226e072919f6
7
- data.tar.gz: '08b4cb3695fb7704010a0bf868fa3465fe6ee7f0a1b5dafc5e90de3fd83295e8b266aec4555ab2f2840becffcb9f5137564781dbfa8edd69698dff091ebb5d98'
6
+ metadata.gz: 35a876c94e0a0c812e92d9e1828996c186a7e9179ada8222265ee30925cb20d91ea67f0047661df4c87eb0508b26752ee50de37ef5078740288bb6cb75c38214
7
+ data.tar.gz: 776f10f0896164550dee36bdae375852b8e374aef9d304c5ddde313202c809fa59ffcf46dbc5a7252464425b695cc62f1536895874c0c4ceeed242d8c41a6763
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.3.0] - 2024-12-11
2
+
3
+ - rename `--exclude` flag to `--excludes`
4
+ - add `--mdcs` flag to include specific MDCs
5
+
1
6
  ## [0.2.0] - 2024-12-05
2
7
 
3
8
  - remove `--pretty` flag
data/README.md CHANGED
@@ -5,16 +5,6 @@
5
5
 
6
6
  > Tail your Kubernetes pod logs at the same time.
7
7
 
8
- > [!NOTE]
9
- > This project is a pet project I used to learn the [Ruby programming language](https://www.ruby-lang.org/en/).
10
- > So you might find lots of my [personal notes](./journey_log.md) in the codebase.
11
- >
12
- > If you want to have something that works, please look at the following
13
- > projects that were used as inspirations instead:
14
- >
15
- > - https://github.com/stern/stern
16
- > - https://github.com/johanhaleby/kubetail
17
-
18
8
  ![kubetailrb](./kubetailrb.png)
19
9
 
20
10
  ## Installation
@@ -51,7 +41,17 @@ kubetailrb 'clock-json' -n sandbox -f
51
41
  kubetailrb '^clock(?!-json)' -n sandbox -f
52
42
 
53
43
  # you can also filter the containers using regex on the container names
54
- kubetailrb 'clock' -n sandbox -f -c 'json'
44
+ kubetailrb 'clock' -n sandbox -f -c 'my-container'
45
+
46
+ # you can exclude access logs
47
+ kubetailrb 'clock' -n sandbox -f --excludes access-logs
48
+ # or Datadog logs
49
+ kubetailrb 'clock' -n sandbox -f --excludes dd-logs
50
+ # or both
51
+ kubetailrb 'clock' -n sandbox -f --excludes access-logs,dd-logs
52
+
53
+ # you can include your MDCs by adding your MDC names separated by a comma
54
+ kubetailrb 'clock' -n sandbox -f --mdcs thread.name,service.version
55
55
  ```
56
56
 
57
57
  ## Development
@@ -94,6 +94,15 @@ Then execute the script:
94
94
 
95
95
  Bug reports and pull requests are welcome on GitHub at https://github.com/l-lin/kubetailrb.
96
96
 
97
+ ## Note
98
+
99
+ This project is a pet project I used to learn the [Ruby programming language](https://www.ruby-lang.org/en/).
100
+ So you might find lots of my [personal notes](./journey_log.md) in the codebase.
101
+
102
+ If you want to have something that is more complete, please look at
103
+ [stern](https://github.com/stern/stern) project that was used as inspirations
104
+ instead.
105
+
97
106
  ## License
98
107
 
99
108
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/kubetailrb.png CHANGED
Binary file
@@ -23,6 +23,8 @@ module Kubetailrb
23
23
  --display-names Display pod and container names.
24
24
  -n, --namespace Kubernetes namespace to use.
25
25
  -c, --container Container name when multiple containers in pod. Default to '.'.
26
+ -e, --excludes Exclude types of log, separated by a comma. Supporting only 'access-logs' and 'dd-logs'.
27
+ -m, --mdcs Include MDCs if present in the JSON log, separated by a comma. E.g. 'account.id,thread.name'.
26
28
  HELP
27
29
  end
28
30
 
@@ -17,7 +17,9 @@ module Kubetailrb
17
17
  DISPLAY_NAMES_FLAG = '--display-names'
18
18
 
19
19
  CONTAINER_FLAGS = %w[-c --container].freeze
20
- EXCLUDE_FLAGS = %w[-e --exclude].freeze
20
+ EXCLUDES_FLAGS = %w[-e --excludes].freeze
21
+
22
+ MDCS_FLAGS = %w[-m --mdcs].freeze
21
23
 
22
24
  attr_reader :reader
23
25
 
@@ -44,7 +46,8 @@ module Kubetailrb
44
46
  follow: parse_follow(*args),
45
47
  raw: parse_raw(*args),
46
48
  display_names: parse_display_names(*args),
47
- exclude: parse_exclude(*args)
49
+ excludes: parse_excludes(*args),
50
+ mdcs: parse_mdcs(*args)
48
51
  )
49
52
  )
50
53
  end
@@ -65,7 +68,7 @@ module Kubetailrb
65
68
  #
66
69
  # will return 'sandbox'.
67
70
  #
68
- # Will raise `MissingNamespaceValueError` if the value is not provided:
71
+ # Will raise `ArgumentError` if the value is not provided:
69
72
  #
70
73
  # kubetailrb some-pod -n
71
74
  #
@@ -74,7 +77,7 @@ module Kubetailrb
74
77
 
75
78
  index = args.find_index { |arg| NAMESPACE_FLAGS.include?(arg) }.to_i
76
79
 
77
- raise MissingNamespaceValueError, "Missing #{NAMESPACE_FLAGS} value." if args[index + 1].nil?
80
+ raise ArgumentError, "Missing #{NAMESPACE_FLAGS} value." if args[index + 1].nil?
78
81
 
79
82
  args[index + 1]
80
83
  end
@@ -86,11 +89,11 @@ module Kubetailrb
86
89
  #
87
90
  # will return 3.
88
91
  #
89
- # Will raise `MissingNbLinesValueError` if the value is not provided:
92
+ # Will raise `ArgumentError` if the value is not provided:
90
93
  #
91
94
  # kubetailrb some-pod --tail
92
95
  #
93
- # Will raise `InvalidNbLinesValueError` if the provided value is not a
96
+ # Will raise `ArgumentError` if the provided value is not a
94
97
  # number:
95
98
  #
96
99
  # kubetailrb some-pod --tail some-string
@@ -100,11 +103,11 @@ module Kubetailrb
100
103
 
101
104
  index = args.find_index { |arg| arg == TAIL_FLAG }.to_i
102
105
 
103
- raise MissingNbLinesValueError, "Missing #{TAIL_FLAG} value." if args[index + 1].nil?
106
+ raise ArgumentError, "Missing #{TAIL_FLAG} value." if args[index + 1].nil?
104
107
 
105
108
  last_nb_lines = args[index + 1].to_i
106
109
 
107
- raise InvalidNbLinesValueError, "Invalid #{TAIL_FLAG} value: #{args[index + 1]}." if last_nb_lines.zero?
110
+ raise ArgumentError, "Invalid #{TAIL_FLAG} value: #{args[index + 1]}." if last_nb_lines.zero?
108
111
 
109
112
  last_nb_lines
110
113
  end
@@ -122,7 +125,7 @@ module Kubetailrb
122
125
 
123
126
  index = args.find_index { |arg| CONTAINER_FLAGS.include?(arg) }.to_i
124
127
 
125
- raise MissingContainerQueryValueError, "Missing #{CONTAINER_FLAGS} value." if args[index + 1].nil?
128
+ raise ArgumentError, "Missing #{CONTAINER_FLAGS} value." if args[index + 1].nil?
126
129
 
127
130
  args[index + 1]
128
131
  end
@@ -138,35 +141,41 @@ module Kubetailrb
138
141
  #
139
142
  # will return [access-logs, dd-logs].
140
143
  #
141
- # Will raise `MissingExcludeValueError` if the value is not provided:
144
+ # Will raise `ArgumentError` if the value is not provided:
142
145
  #
143
146
  # kubetailrb some-pod --exclude
144
147
  #
145
- def parse_exclude(*args)
146
- return [] unless args.any? { |arg| EXCLUDE_FLAGS.include?(arg) }
148
+ def parse_excludes(*args)
149
+ return [] unless args.any? { |arg| EXCLUDES_FLAGS.include?(arg) }
147
150
 
148
- index = args.find_index { |arg| EXCLUDE_FLAGS.include?(arg) }.to_i
151
+ index = args.find_index { |arg| EXCLUDES_FLAGS.include?(arg) }.to_i
149
152
 
150
- raise MissingExcludeValueError, "Missing #{EXCLUDE_FLAGS} value." if args[index + 1].nil?
153
+ raise ArgumentError, "Missing #{EXCLUDES_FLAGS} value." if args[index + 1].nil?
151
154
 
152
155
  args[index + 1].split(',')
153
156
  end
154
- end
155
- end
156
-
157
- class MissingNbLinesValueError < RuntimeError
158
- end
159
157
 
160
- class MissingNamespaceValueError < RuntimeError
161
- end
158
+ #
159
+ # Parse MDCs to include from arguments provided in the CLI, e.g.
160
+ #
161
+ # kubetailrb some-pod --mdc account.id,process.thread.name
162
+ #
163
+ # will return [account.id, thread.name].
164
+ #
165
+ # Will raise `ArgumentError` if the value is not provided:
166
+ #
167
+ # kubetailrb some-pod --mdc
168
+ #
169
+ def parse_mdcs(*args)
170
+ return [] unless args.any? { |arg| MDCS_FLAGS.include?(arg) }
162
171
 
163
- class MissingContainerQueryValueError < RuntimeError
164
- end
172
+ index = args.find_index { |arg| MDCS_FLAGS.include?(arg) }.to_i
165
173
 
166
- class MissingExcludeValueError < RuntimeError
167
- end
174
+ raise ArgumentError, "Missing #{MDCS_FLAGS} value." if args[index + 1].nil?
168
175
 
169
- class InvalidNbLinesValueError < RuntimeError
176
+ args[index + 1].split(',')
177
+ end
178
+ end
170
179
  end
171
180
  end
172
181
  end
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kubetailrb/painter'
4
+ require 'kubetailrb/validated'
4
5
 
5
6
  module Kubetailrb
6
7
  module Formatter
7
8
  # Format JSON to human readable.
8
9
  class JsonFormatter
9
10
  include Painter
11
+ include Validated
12
+
13
+ def initialize(mdcs = [])
14
+ @mdcs = mdcs
15
+
16
+ validate
17
+ end
10
18
 
11
19
  def format(log)
12
20
  json = JSON.parse(log)
@@ -20,16 +28,20 @@ module Kubetailrb
20
28
 
21
29
  private
22
30
 
31
+ def validate
32
+ raise_if_nil @mdcs, 'MDCs not set.'
33
+ end
34
+
23
35
  def access_log?(json)
24
36
  json.include?('http.response.status_code') || json.include?('http_status')
25
37
  end
26
38
 
27
39
  def format_access_log(json)
28
- "#{json["@timestamp"]}#{http_status_code json}#{http_method json} #{url_path json}"
40
+ "#{json["@timestamp"]}#{format_http_status_code json}#{http_method json} #{url_path json}"
29
41
  end
30
42
 
31
43
  def format_application_log(json)
32
- "#{json["@timestamp"]}#{log_level json}#{json["message"]}#{format_stack_trace json}"
44
+ "#{json["@timestamp"]}#{format_log_level json}#{format_mdcs json}#{json["message"]}#{format_stack_trace json}"
33
45
  end
34
46
 
35
47
  def format_stack_trace(json)
@@ -40,7 +52,7 @@ module Kubetailrb
40
52
  "\n#{stack_trace}"
41
53
  end
42
54
 
43
- def http_status_code(json)
55
+ def format_http_status_code(json)
44
56
  code = json['http.response.status_code'] || json['http_status']
45
57
 
46
58
  return " #{highlight_blue(" I ")} [#{code}] " if code >= 200 && code < 400
@@ -50,7 +62,7 @@ module Kubetailrb
50
62
  " #{code} "
51
63
  end
52
64
 
53
- def log_level(json)
65
+ def format_log_level(json)
54
66
  level = json['log.level'] || json.dig('log', 'level')
55
67
  return ' ' if level.nil? || level.strip.empty?
56
68
  return " #{highlight_blue(" I ")} " if level == 'INFO'
@@ -67,6 +79,15 @@ module Kubetailrb
67
79
  def url_path(json)
68
80
  json['url.path'] || json['http_path']
69
81
  end
82
+
83
+ def format_mdcs(json)
84
+ result = ''
85
+ @mdcs.each do |mdc|
86
+ value = json[mdc] || json.dig(*mdc.split('.'))
87
+ result += "#{cyan("#{mdc}=#{value}")} " unless value.nil?
88
+ end
89
+ result.to_s
90
+ end
70
91
  end
71
92
  end
72
93
  end
@@ -7,15 +7,27 @@ module Kubetailrb
7
7
  class K8sOpts
8
8
  include Validated
9
9
 
10
- attr_reader :namespace, :last_nb_lines, :exclude
11
-
12
- def initialize(namespace:, last_nb_lines:, follow:, raw:, display_names:, exclude:) # rubocop:disable Metrics/ParameterLists
10
+ DEFAULT_NAMESPACE = 'default'
11
+ DEFAULT_NB_LINES = 10
12
+
13
+ attr_reader :namespace, :last_nb_lines, :excludes, :mdcs
14
+
15
+ def initialize( # rubocop:disable Metrics/ParameterLists
16
+ namespace: DEFAULT_NAMESPACE,
17
+ last_nb_lines: DEFAULT_NB_LINES,
18
+ follow: false,
19
+ raw: false,
20
+ display_names: false,
21
+ excludes: [],
22
+ mdcs: []
23
+ )
13
24
  @namespace = namespace
14
25
  @last_nb_lines = last_nb_lines
15
26
  @follow = follow
16
27
  @raw = raw
17
28
  @display_names = display_names
18
- @exclude = exclude
29
+ @excludes = excludes
30
+ @mdcs = mdcs
19
31
 
20
32
  validate
21
33
  end
@@ -40,7 +52,8 @@ module Kubetailrb
40
52
  validate_boolean @follow, "Invalid follow: #{@follow}."
41
53
  validate_boolean @raw, "Invalid raw: #{@raw}."
42
54
  validate_boolean @display_names, "Invalid display names: #{@display_names}."
43
- raise_if_nil @exclude, 'Exclude not set'
55
+ raise_if_nil @excludes, 'Excludes not set.'
56
+ raise_if_nil @mdcs, 'MDCs not set.'
44
57
  end
45
58
  end
46
59
  end
@@ -11,6 +11,10 @@ module Kubetailrb
11
11
  colorize(text, '31')
12
12
  end
13
13
 
14
+ def cyan(text)
15
+ colorize(text, '36')
16
+ end
17
+
14
18
  def highlight_blue(text)
15
19
  colorize(text, '1;30;44')
16
20
  end
@@ -23,7 +23,7 @@ module Kubetailrb
23
23
  @pod_name = pod_name
24
24
  @container_name = container_name
25
25
  @formatter = create_formatter(opts, pod_name, container_name)
26
- @filter = Kubetailrb::Filter::LogFilter.create(opts.exclude)
26
+ @filter = Kubetailrb::Filter::LogFilter.create(opts.excludes)
27
27
  @opts = opts
28
28
  end
29
29
 
@@ -95,7 +95,7 @@ module Kubetailrb
95
95
  formatter = if opts.raw?
96
96
  Kubetailrb::Formatter::NoOpFormatter.new
97
97
  else
98
- Kubetailrb::Formatter::JsonFormatter.new
98
+ Kubetailrb::Formatter::JsonFormatter.new(opts.mdcs)
99
99
  end
100
100
 
101
101
  if opts.display_names?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kubetailrb
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubetailrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Louis Lin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-05 00:00:00.000000000 Z
11
+ date: 2024-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kubeclient