gooddata 1.3.6-java → 2.0.0-java
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +54 -36
- data/CHANGELOG.md +37 -1
- data/CONTRIBUTING.md +4 -0
- data/Gemfile +9 -0
- data/Jenkinsfile-chart +14 -0
- data/RELEASING.md +5 -8
- data/Rakefile +1 -1
- data/SDK_VERSION +1 -1
- data/bin/run_brick.rb +1 -1
- data/bin/test_projects_cleanup.rb +20 -8
- data/ci.rake +2 -2
- data/k8s/charts/lcm-bricks/Chart.yaml +4 -0
- data/k8s/charts/lcm-bricks/templates/prometheus/alertingRules.yaml +96 -0
- data/lcm.rake +1 -1
- data/lib/gooddata/bricks/middleware/context_logger_decorator.rb +31 -0
- data/lib/gooddata/bricks/middleware/context_manager.rb +68 -0
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +15 -9
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +20 -0
- data/lib/gooddata/bricks/middleware/mask_logger_decorator.rb +35 -5
- data/lib/gooddata/client.rb +2 -3
- data/lib/gooddata/core/gd_logger.rb +92 -0
- data/lib/gooddata/core/logging.rb +24 -7
- data/lib/gooddata/core/nil_logger.rb +1 -2
- data/lib/gooddata/core/splunk_logger.rb +23 -0
- data/lib/gooddata/lcm/actions/synchronize_users.rb +2 -1
- data/lib/gooddata/lcm/helpers/check_helper.rb +3 -15
- data/lib/gooddata/lcm/helpers/safe_failure_helper.rb +19 -0
- data/lib/gooddata/lcm/lcm2.rb +21 -10
- data/lib/gooddata/mixins/property_accessor.rb +30 -0
- data/lib/gooddata/models/execution.rb +5 -0
- data/lib/gooddata/models/project.rb +6 -4
- data/lib/gooddata/rest/client.rb +17 -6
- data/lib/gooddata/rest/connection.rb +20 -6
- data/lib/gooddata/rest/rest_aggregator.rb +46 -0
- metadata +12 -2
@@ -0,0 +1,68 @@
|
|
1
|
+
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
|
2
|
+
# This source code is licensed under the BSD-style license found in the
|
3
|
+
# LICENSE file in the root directory of this source tree.
|
4
|
+
|
5
|
+
require_relative '../../mixins/property_accessor'
|
6
|
+
require_relative '../../lcm/helpers/helpers'
|
7
|
+
|
8
|
+
module GoodData
|
9
|
+
module ContextManager
|
10
|
+
extend GoodData::Mixin::PropertyAccessor
|
11
|
+
|
12
|
+
property_accessor :@context, :action
|
13
|
+
property_accessor :@context, :brick
|
14
|
+
property_accessor :@context, :execution_id
|
15
|
+
property_accessor :@context, :status
|
16
|
+
|
17
|
+
def initialize_context
|
18
|
+
@action_start = Time.now
|
19
|
+
|
20
|
+
# :log_v is used to differentiate new versions of logs in splunk
|
21
|
+
@context = {
|
22
|
+
:api_version => GoodData.version,
|
23
|
+
:log_v => 0,
|
24
|
+
:component => 'lcm.ruby',
|
25
|
+
:status => :not_in_action
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return current brick context extended with time specific information
|
30
|
+
#
|
31
|
+
# @param [Time] now, allows to specify exact time, when outer call was performed
|
32
|
+
# @return [Hash] Brick context
|
33
|
+
def context(now = Time.now)
|
34
|
+
time_specific_context = action ? { :time => time_from_action_start(now) } : {}
|
35
|
+
@context.merge(time_specific_context)
|
36
|
+
end
|
37
|
+
|
38
|
+
def time_from_action_start(now = Time.now)
|
39
|
+
fail_if_development 'No action is being profiled' unless action
|
40
|
+
(now - @action_start) * 1000
|
41
|
+
end
|
42
|
+
|
43
|
+
# Starts lcm action
|
44
|
+
#
|
45
|
+
# @param [String] action, name of the action
|
46
|
+
# @param [Logger] logger, logger that should log current context info
|
47
|
+
# @param [Time] now, allows to specify exact time, when outer call was performed
|
48
|
+
def start_action(next_action, logger = nil, now = Time.now)
|
49
|
+
fail_if_development 'An action is already being profiled' if action
|
50
|
+
|
51
|
+
self.action = next_action
|
52
|
+
@action_start = now
|
53
|
+
logger.info '' if logger
|
54
|
+
self.status = :action_in_progress
|
55
|
+
end
|
56
|
+
|
57
|
+
# Ends currently opened lcm action
|
58
|
+
#
|
59
|
+
# @param [Logger] logger, logger that should log current context info
|
60
|
+
def end_action(logger = nil)
|
61
|
+
fail_if_development 'No matching action to start found' unless action
|
62
|
+
|
63
|
+
logger.info '' if logger
|
64
|
+
self.status = :not_in_action
|
65
|
+
self.action = nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -26,6 +26,9 @@ module GoodData
|
|
26
26
|
DEFAULT_HOSTNAME = 'secure.gooddata.com'
|
27
27
|
|
28
28
|
def call(params)
|
29
|
+
# Generate brick execution id
|
30
|
+
execution_id = GoodData.gd_logger.execution_id
|
31
|
+
|
29
32
|
# Convert possible jruby hash to plain hash
|
30
33
|
params = params.to_hash
|
31
34
|
|
@@ -48,7 +51,8 @@ module GoodData
|
|
48
51
|
params['GDC_VERIFY_SSL'].to_b,
|
49
52
|
params['GDC_USERNAME'],
|
50
53
|
params['GDC_PASSWORD'],
|
51
|
-
params['GDC_SST']
|
54
|
+
params['GDC_SST'],
|
55
|
+
execution_id
|
52
56
|
)
|
53
57
|
|
54
58
|
opts = params['development_client']
|
@@ -66,7 +70,8 @@ module GoodData
|
|
66
70
|
opts['verify_ssl'].to_b,
|
67
71
|
opts['username'] || opts['login'] || opts['email'],
|
68
72
|
opts['password'],
|
69
|
-
opts['sst']
|
73
|
+
opts['sst'],
|
74
|
+
execution_id
|
70
75
|
)
|
71
76
|
else
|
72
77
|
development_client = client
|
@@ -77,6 +82,7 @@ module GoodData
|
|
77
82
|
'development_client' => development_client
|
78
83
|
}
|
79
84
|
|
85
|
+
# collect parent project if deployed as process
|
80
86
|
if params['GDC_PROJECT_ID']
|
81
87
|
new_params['gdc_project'] = GoodData.project = client.projects(params['GDC_PROJECT_ID'])
|
82
88
|
end
|
@@ -86,29 +92,29 @@ module GoodData
|
|
86
92
|
# Try to disconnect client
|
87
93
|
begin
|
88
94
|
client.disconnect
|
89
|
-
rescue
|
90
|
-
GoodData.logger.warn(
|
95
|
+
rescue StandardError => e
|
96
|
+
GoodData.logger.warn("Tried to disconnect client. Was unsuccessful. Proceeding anyway. Error: #{e}")
|
91
97
|
end
|
92
98
|
|
93
99
|
# Try to disconnect development_client
|
94
100
|
begin
|
95
101
|
development_client.disconnect if development_client != client
|
96
|
-
rescue
|
97
|
-
GoodData.logger.warn(
|
102
|
+
rescue StandardError => e
|
103
|
+
GoodData.logger.warn("Tried to disconnect development_client. Was unsuccessful. Proceeding anyway. Error: #{e}")
|
98
104
|
end
|
99
105
|
|
100
106
|
returning_value
|
101
107
|
end
|
102
108
|
|
103
109
|
class << self
|
104
|
-
def connect(server, verify_ssl, username, password, sst_token) # rubocop:disable Metrics/ParameterLists
|
110
|
+
def connect(server, verify_ssl, username, password, sst_token, execution_id) # rubocop:disable Metrics/ParameterLists
|
105
111
|
if username.nil? || password.nil?
|
106
112
|
GoodData.logger.info("Connecting with SST to server #{server}")
|
107
113
|
raise 'SST (SuperSecureToken) not present in params' if sst_token.nil?
|
108
|
-
conn = GoodData.connect(sst_token: sst_token, server: server, verify_ssl: verify_ssl)
|
114
|
+
conn = GoodData.connect(sst_token: sst_token, server: server, verify_ssl: verify_ssl, execution_id: execution_id)
|
109
115
|
else
|
110
116
|
GoodData.logger.info("Connecting as #{username} to server #{server}")
|
111
|
-
conn = GoodData.connect(username, password, server: server, verify_ssl: verify_ssl)
|
117
|
+
conn = GoodData.connect(username, password, server: server, verify_ssl: verify_ssl, execution_id: execution_id)
|
112
118
|
end
|
113
119
|
conn.stats_on
|
114
120
|
|
@@ -5,6 +5,7 @@
|
|
5
5
|
# LICENSE file in the root directory of this source tree.
|
6
6
|
|
7
7
|
require 'logger'
|
8
|
+
require 'gooddata/core/splunk_logger'
|
8
9
|
|
9
10
|
require 'gooddata/extensions/true'
|
10
11
|
require 'gooddata/extensions/false'
|
@@ -20,6 +21,7 @@ using NilExtensions
|
|
20
21
|
|
21
22
|
require_relative 'base_middleware'
|
22
23
|
require_relative 'mask_logger_decorator'
|
24
|
+
require_relative 'context_logger_decorator'
|
23
25
|
|
24
26
|
module GoodData
|
25
27
|
module Bricks
|
@@ -45,6 +47,24 @@ module GoodData
|
|
45
47
|
params['GDC_LOGGER'] = logger
|
46
48
|
GoodData.logging_http_on if params['HTTP_LOGGING'] && params['HTTP_LOGGING'].to_b
|
47
49
|
|
50
|
+
# Initialize splunk logger
|
51
|
+
if params['SPLUNK_LOGGING'] && params['SPLUNK_LOGGING'].to_b
|
52
|
+
GoodData.logger.info "Statistics collecting is turned ON. All the data is anonymous."
|
53
|
+
splunk_logger = SplunkLogger.new params['SPLUNK_LOG_PATH'] || GoodData::DEFAULT_SPLUNKLOG_OUTPUT
|
54
|
+
splunk_logger.level = params['SPLUNK_LOG_LEVEL'] || GoodData::DEFAULT_SPLUNKLOG_LEVEL
|
55
|
+
splunk_logger = splunk_logger.extend(ContextLoggerDecorator)
|
56
|
+
splunk_logger.context_source = GoodData.gd_logger
|
57
|
+
values_to_mask = params['values_to_mask'] || []
|
58
|
+
values_to_mask.concat MaskLoggerDecorator.extract_values params
|
59
|
+
splunk_logger = MaskLoggerDecorator.new(splunk_logger, values_to_mask) if values_to_mask.any?
|
60
|
+
else
|
61
|
+
splunk_logger = NilLogger.new
|
62
|
+
end
|
63
|
+
GoodData.splunk_logging_on splunk_logger
|
64
|
+
|
65
|
+
# Initialize context: Execution ID
|
66
|
+
GoodData.gd_logger.execution_id = params['GDC_EXECUTION_ID'] || SecureRandom.urlsafe_base64(16)
|
67
|
+
|
48
68
|
returning(@app.call(params)) do |_result|
|
49
69
|
logger.info('Pipeline ending')
|
50
70
|
end
|
@@ -14,6 +14,24 @@ module GoodData
|
|
14
14
|
@values_to_mask = values_to_mask
|
15
15
|
end
|
16
16
|
|
17
|
+
class << self
|
18
|
+
# Extract values to mask from structured data
|
19
|
+
# @param values [String] or [Hash] or [Array] structured data to be extracted
|
20
|
+
# @return [[String]] array of all String in values
|
21
|
+
def extract_values(values)
|
22
|
+
if values.is_a?(String)
|
23
|
+
[values]
|
24
|
+
elsif values.is_a?(Hash) || values.is_a?(Array)
|
25
|
+
(values.is_a?(Hash) ? values.values : values).reduce([]) do |strings, item|
|
26
|
+
strings.concat extract_values(item)
|
27
|
+
strings
|
28
|
+
end
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
17
35
|
# log methods to be decorated
|
18
36
|
%i[debug error fatal info unknown warn].each do |level|
|
19
37
|
define_method level do |message|
|
@@ -21,14 +39,26 @@ module GoodData
|
|
21
39
|
end
|
22
40
|
end
|
23
41
|
|
24
|
-
|
42
|
+
# Decorator pretends being inner logger itselfs.
|
43
|
+
# @return inner logger class
|
44
|
+
def class
|
45
|
+
@logger.class
|
46
|
+
end
|
47
|
+
|
48
|
+
def add(severity, message = nil, progname = nil)
|
49
|
+
mask message
|
50
|
+
mask progname
|
51
|
+
@logger.add(severity, message, progname)
|
52
|
+
end
|
25
53
|
|
26
|
-
# Masks given message
|
27
|
-
# @param message
|
28
|
-
# @return masked_message [String] masked message
|
54
|
+
# Masks given message
|
55
|
+
# @param message [String] or [Hash] or [Array] message to mask
|
56
|
+
# @return masked_message [String] or [Hash] or [Array] masked message
|
29
57
|
def mask(message)
|
30
58
|
unless message.nil?
|
31
|
-
|
59
|
+
string = message.to_s
|
60
|
+
|
61
|
+
@values_to_mask.reduce(string) do |masked_message, value_to_mask|
|
32
62
|
masked_message.gsub(value_to_mask, "******")
|
33
63
|
end
|
34
64
|
end
|
data/lib/gooddata/client.rb
CHANGED
@@ -42,8 +42,6 @@ require_relative 'core/core'
|
|
42
42
|
|
43
43
|
module GoodData
|
44
44
|
class << self
|
45
|
-
RELEASE_INFO_PATH = '/gdc/releaseInfo'
|
46
|
-
|
47
45
|
# Initializes required dynamically loaded classes
|
48
46
|
def init_module
|
49
47
|
# Metadata packages, such as report.rb, require this to be loaded first
|
@@ -57,8 +55,9 @@ module GoodData
|
|
57
55
|
end
|
58
56
|
|
59
57
|
# Returns information about the GoodData API as a Hash (e.g. version, release time etc.)
|
58
|
+
# @deprecated The release info endpoint has been deprecated without a replacement.
|
60
59
|
def release_info
|
61
|
-
|
60
|
+
fail 'The release info endpoint has been deprecated without a replacement.'
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
|
2
|
+
# This source code is licensed under the BSD-style license found in the
|
3
|
+
# LICENSE file in the root directory of this source tree.
|
4
|
+
|
5
|
+
require 'logger'
|
6
|
+
require 'gooddata/bricks/middleware/context_manager'
|
7
|
+
require 'gooddata/rest/rest_aggregator'
|
8
|
+
|
9
|
+
module GoodData
|
10
|
+
# This class delegates messages to multiple loggers
|
11
|
+
# By usage of [ContextManager] and [Rest::Aggregator] it stores information about context of execution
|
12
|
+
class GdLogger
|
13
|
+
severity_map = {
|
14
|
+
debug: Logger::DEBUG,
|
15
|
+
info: Logger::INFO,
|
16
|
+
warn: Logger::WARN,
|
17
|
+
error: Logger::ERROR,
|
18
|
+
fatal: Logger::FATAL,
|
19
|
+
unknown: Logger::UNKNOWN
|
20
|
+
}
|
21
|
+
|
22
|
+
attr_accessor :loggers
|
23
|
+
|
24
|
+
include ContextManager
|
25
|
+
include GoodData::Rest::Aggregator
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@loggers = {}
|
29
|
+
initialize_context
|
30
|
+
initialize_store
|
31
|
+
end
|
32
|
+
|
33
|
+
def logging_on(logger_id, logger)
|
34
|
+
loggers[logger_id] = logger
|
35
|
+
end
|
36
|
+
|
37
|
+
def logging_off(logger_id)
|
38
|
+
loggers[logger_id] = NilLogger.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def logging_on?(logger_id)
|
42
|
+
loggers.key?(logger_id) && !loggers[logger_id].is_a?(NilLogger)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Implementation of common logger methods
|
46
|
+
%i[debug error fatal info unknown warn].each do |severity|
|
47
|
+
# GdLogger delegates all records to all loggers
|
48
|
+
define_method severity do |progname = nil, &block|
|
49
|
+
add(severity_map[severity], nil, progname, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns [True] if any logger satisfies severity level
|
53
|
+
define_method severity.to_s + "?" do
|
54
|
+
test_severity severity
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_severity(severity)
|
59
|
+
(loggers.values.map do |logger|
|
60
|
+
logger.send severity.to_s + "?"
|
61
|
+
end).any?
|
62
|
+
end
|
63
|
+
|
64
|
+
# Pass message to multiple loggers. By parameters some loggers might be filtered out and the message might be modified.
|
65
|
+
#
|
66
|
+
# @param severity, severity of record
|
67
|
+
# @param message, message to be logged
|
68
|
+
# @param progname, progname to be logged
|
69
|
+
def add(severity, message, progname, &block)
|
70
|
+
loggers.each do |_, logger|
|
71
|
+
logger.add(severity, message, progname, &block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set logger level for specified logger
|
76
|
+
#
|
77
|
+
# @param level, severity level
|
78
|
+
# @param [Symbol] logger_name, logger which severity level should be changed
|
79
|
+
def level(level, logger_name)
|
80
|
+
loggers[logger_name].level = level
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set logger level for all loggers
|
84
|
+
#
|
85
|
+
# @param level, severity level
|
86
|
+
def level=(level)
|
87
|
+
loggers.values.each do |logger|
|
88
|
+
logger.level = level
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -7,6 +7,8 @@
|
|
7
7
|
require 'rest-client'
|
8
8
|
|
9
9
|
require_relative 'nil_logger'
|
10
|
+
require_relative 'splunk_logger'
|
11
|
+
require_relative 'gd_logger'
|
10
12
|
|
11
13
|
module GoodData
|
12
14
|
DEFAULT_LOG_LEVEL = Logger::INFO
|
@@ -17,8 +19,12 @@ module GoodData
|
|
17
19
|
DEFAULT_RESTLOG_OUTPUT = STDOUT
|
18
20
|
DEFAULT_RESTLOGGER_CLASS = Logger
|
19
21
|
|
22
|
+
DEFAULT_SPLUNKLOG_LEVEL = Logger::INFO
|
23
|
+
DEFAULT_SPLUNKLOG_OUTPUT = STDERR
|
24
|
+
DEFAULT_SPLUNKLOGGER_CLASS = SplunkLogger
|
25
|
+
|
20
26
|
class << self
|
21
|
-
attr_accessor :logger, :rest_logger
|
27
|
+
attr_accessor :logger, :rest_logger, :gd_logger
|
22
28
|
attr_writer :stats
|
23
29
|
|
24
30
|
# Turn logging on
|
@@ -80,16 +86,23 @@ module GoodData
|
|
80
86
|
!@rest_logger.instance_of?(NilLogger)
|
81
87
|
end
|
82
88
|
|
83
|
-
|
84
|
-
|
89
|
+
# Turn splunk logging on
|
90
|
+
def splunk_logging_on(logger)
|
91
|
+
gd_logger.logging_on :splunk, logger
|
85
92
|
end
|
86
93
|
|
87
|
-
|
88
|
-
|
94
|
+
# Turn splunk logging off
|
95
|
+
#
|
96
|
+
# ### Example
|
97
|
+
#
|
98
|
+
# GoodData.logging_splunk_off
|
99
|
+
#
|
100
|
+
def splunk_logging_off
|
101
|
+
gd_logger.logging_off :splunk
|
89
102
|
end
|
90
103
|
|
91
|
-
def
|
92
|
-
|
104
|
+
def splunk_logging_on?
|
105
|
+
gd_logger.logging_on? :splunk
|
93
106
|
end
|
94
107
|
|
95
108
|
# Initial setup of logger
|
@@ -101,5 +114,9 @@ module GoodData
|
|
101
114
|
DEFAULT_RESTLOG_OUTPUT,
|
102
115
|
NilLogger
|
103
116
|
)
|
117
|
+
|
118
|
+
# Initial setup of splunk logger
|
119
|
+
GoodData.gd_logger = GdLogger.new
|
120
|
+
GoodData.splunk_logging_off
|
104
121
|
end
|
105
122
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
1
|
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
|
4
2
|
# This source code is licensed under the BSD-style license found in the
|
5
3
|
# LICENSE file in the root directory of this source tree.
|
@@ -19,6 +17,7 @@ module GoodData
|
|
19
17
|
alias_method :info, :debug
|
20
18
|
alias_method :warn, :debug
|
21
19
|
alias_method :error, :debug
|
20
|
+
alias_method :add, :debug
|
22
21
|
|
23
22
|
def debug?
|
24
23
|
false
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
|
2
|
+
# This source code is licensed under the BSD-style license found in the
|
3
|
+
# LICENSE file in the root directory of this source tree.
|
4
|
+
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
module GoodData
|
8
|
+
# Logger that process given message to format readable by splunk
|
9
|
+
class SplunkLogger < Logger
|
10
|
+
def hash_to_string(hash)
|
11
|
+
hash.map { |pair| " #{pair[0]}=#{pair[1]}" }.join ""
|
12
|
+
end
|
13
|
+
|
14
|
+
# If the given message or progname is an instance of Hash, it's reformatted to splunk readable format.
|
15
|
+
# In case that the message or the progname contain new line character log won't be printed out.
|
16
|
+
# Otherwise splunk worker wouldn't process it correctly.
|
17
|
+
def add(severity, message = nil, progname = nil)
|
18
|
+
message = hash_to_string(message) if message.is_a? Hash
|
19
|
+
progname = hash_to_string(progname) if progname.is_a? Hash
|
20
|
+
super(severity, message, progname) unless (progname && progname.include?("\n")) || (message && message.include?("\n"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|