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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +54 -36
  4. data/CHANGELOG.md +37 -1
  5. data/CONTRIBUTING.md +4 -0
  6. data/Gemfile +9 -0
  7. data/Jenkinsfile-chart +14 -0
  8. data/RELEASING.md +5 -8
  9. data/Rakefile +1 -1
  10. data/SDK_VERSION +1 -1
  11. data/bin/run_brick.rb +1 -1
  12. data/bin/test_projects_cleanup.rb +20 -8
  13. data/ci.rake +2 -2
  14. data/k8s/charts/lcm-bricks/Chart.yaml +4 -0
  15. data/k8s/charts/lcm-bricks/templates/prometheus/alertingRules.yaml +96 -0
  16. data/lcm.rake +1 -1
  17. data/lib/gooddata/bricks/middleware/context_logger_decorator.rb +31 -0
  18. data/lib/gooddata/bricks/middleware/context_manager.rb +68 -0
  19. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +15 -9
  20. data/lib/gooddata/bricks/middleware/logger_middleware.rb +20 -0
  21. data/lib/gooddata/bricks/middleware/mask_logger_decorator.rb +35 -5
  22. data/lib/gooddata/client.rb +2 -3
  23. data/lib/gooddata/core/gd_logger.rb +92 -0
  24. data/lib/gooddata/core/logging.rb +24 -7
  25. data/lib/gooddata/core/nil_logger.rb +1 -2
  26. data/lib/gooddata/core/splunk_logger.rb +23 -0
  27. data/lib/gooddata/lcm/actions/synchronize_users.rb +2 -1
  28. data/lib/gooddata/lcm/helpers/check_helper.rb +3 -15
  29. data/lib/gooddata/lcm/helpers/safe_failure_helper.rb +19 -0
  30. data/lib/gooddata/lcm/lcm2.rb +21 -10
  31. data/lib/gooddata/mixins/property_accessor.rb +30 -0
  32. data/lib/gooddata/models/execution.rb +5 -0
  33. data/lib/gooddata/models/project.rb +6 -4
  34. data/lib/gooddata/rest/client.rb +17 -6
  35. data/lib/gooddata/rest/connection.rb +20 -6
  36. data/lib/gooddata/rest/rest_aggregator.rb +46 -0
  37. 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('Tried to disconnect client. Was unsuccessful. Proceeding anyway.')
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('Tried to disconnect development_client. Was unsuccessful. Proceeding anyway.')
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
- private
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 [String] message to mask
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
- @values_to_mask.reduce(message) do |masked_message, value_to_mask|
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
@@ -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
- @release_info ||= @connection.get(RELEASE_INFO_PATH)['release']
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
- def stats_on
84
- @stats = true
89
+ # Turn splunk logging on
90
+ def splunk_logging_on(logger)
91
+ gd_logger.logging_on :splunk, logger
85
92
  end
86
93
 
87
- def stats_on?
88
- @stats
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 stats_off
92
- @stats = false
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