Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/pod_logs/kubernetes_service.rb')
-rw-r--r--app/services/pod_logs/kubernetes_service.rb88
1 files changed, 88 insertions, 0 deletions
diff --git a/app/services/pod_logs/kubernetes_service.rb b/app/services/pod_logs/kubernetes_service.rb
new file mode 100644
index 00000000000..8f12b364e73
--- /dev/null
+++ b/app/services/pod_logs/kubernetes_service.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module PodLogs
+ class KubernetesService < BaseService
+ LOGS_LIMIT = 500.freeze
+ REPLACEMENT_CHAR = "\u{FFFD}"
+
+ EncodingHelperError = Class.new(StandardError)
+
+ steps :check_arguments,
+ :check_param_lengths,
+ :get_raw_pods,
+ :get_pod_names,
+ :check_pod_name,
+ :check_container_name,
+ :pod_logs,
+ :encode_logs_to_utf8,
+ :split_logs,
+ :filter_return_keys
+
+ self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
+
+ private
+
+ def pod_logs(result)
+ result[:logs] = cluster.kubeclient.get_pod_log(
+ result[:pod_name],
+ namespace,
+ container: result[:container_name],
+ tail_lines: LOGS_LIMIT,
+ timestamps: true
+ ).body
+
+ success(result)
+ rescue Kubeclient::ResourceNotFoundError
+ error(_('Pod not found'))
+ rescue Kubeclient::HttpError => e
+ ::Gitlab::ErrorTracking.track_exception(e)
+
+ error(_('Kubernetes API returned status code: %{error_code}') % {
+ error_code: e.error_code
+ })
+ end
+
+ # Check https://gitlab.com/gitlab-org/gitlab/issues/34965#note_292261879
+ # for more details on why this is necessary.
+ def encode_logs_to_utf8(result)
+ return success(result) if result[:logs].nil?
+ return success(result) if result[:logs].encoding == Encoding::UTF_8
+
+ result[:logs] = encode_utf8(result[:logs])
+
+ success(result)
+ rescue EncodingHelperError
+ error(_('Unable to convert Kubernetes logs encoding to UTF-8'))
+ end
+
+ def split_logs(result)
+ result[:logs] = result[:logs].strip.lines(chomp: true).map do |line|
+ # message contains a RFC3339Nano timestamp, then a space, then the log line.
+ # resolution of the nanoseconds can vary, so we split on the first space
+ values = line.split(' ', 2)
+ {
+ timestamp: values[0],
+ message: values[1]
+ }
+ end
+
+ success(result)
+ end
+
+ def encode_utf8(logs)
+ utf8_logs = Gitlab::EncodingHelper.encode_utf8(logs.dup, replace: REPLACEMENT_CHAR)
+
+ # Gitlab::EncodingHelper.encode_utf8 can return '' or nil if an exception
+ # is raised while encoding. We prefer to return an error rather than wrongly
+ # display blank logs.
+ no_utf8_logs = logs.present? && utf8_logs.blank?
+ unexpected_encoding = utf8_logs&.encoding != Encoding::UTF_8
+
+ if no_utf8_logs || unexpected_encoding
+ raise EncodingHelperError, 'Could not convert Kubernetes logs to UTF-8'
+ end
+
+ utf8_logs
+ end
+ end
+end