google-cloud-logging 0.20.1 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "google/cloud/logging"
16
+
17
+ module Google
18
+ module Cloud
19
+ module Logging
20
+ ##
21
+ # Default log name to be used for Stackdriver Logging
22
+ DEFAULT_LOG_NAME = "ruby_app_log"
23
+
24
+ ##
25
+ # Railtie
26
+ #
27
+ # Google::Cloud::Logging::Railtie automatically add the
28
+ # Google::Cloud::Logging::Middleware to Rack in a Rails environment.
29
+ # The middleware will set env['rack.logger'] to a
30
+ # Google::Cloud::Logging::Logger instance to be used by the Rails
31
+ # application.
32
+ #
33
+ # The Middleware is only added when certain conditions are met. See
34
+ # {use_logging?} for detail.
35
+ #
36
+ # When loaded, the Google::Cloud::Logging::Middleware will be inserted
37
+ # before the Rails::Rack::Logger Middleware, which allows it to set the
38
+ # env['rack.logger'] in place of Rails's default logger. The Railtie
39
+ # should also initialize the logger with correct GCP project_id
40
+ # and keyfile if they are defined in Rails environment.rb as follow:
41
+ # config.google_cloud.logging.project_id = "my-gcp-project"
42
+ # config.google_cloud.logging.keyfile = "/path/to/secret.json"
43
+ # or
44
+ # config.google_cloud.project_id = "my-gcp-project"
45
+ # config.google_cloud.keyfile = "/path/to/secret.json"
46
+ # If omitted, project_id will be initialized with default environment
47
+ # variables.
48
+ #
49
+ class Railtie < ::Rails::Railtie
50
+ config.google_cloud = ::ActiveSupport::OrderedOptions.new unless
51
+ config.respond_to? :google_cloud
52
+ config.google_cloud.logging = ::ActiveSupport::OrderedOptions.new
53
+
54
+ initializer "Stackdriver.Logging", before: :initialize_logger do |app|
55
+ if self.class.use_logging? app.config
56
+ gcp_config = app.config.google_cloud
57
+ log_config = gcp_config.logging
58
+
59
+ project_id = log_config.project_id || gcp_config.project_id
60
+ keyfile = log_config.keyfile || gcp_config.keyfile
61
+
62
+ logging = Google::Cloud::Logging.new project: project_id,
63
+ keyfile: keyfile
64
+ resource =
65
+ Google::Cloud::Logging::Middleware.build_monitoring_resource
66
+ log_name = log_config.log_name || DEFAULT_LOG_NAME
67
+
68
+ app.config.logger = Google::Cloud::Logging::Logger.new logging,
69
+ log_name,
70
+ resource
71
+ app.middleware.insert_before Rails::Rack::Logger,
72
+ Google::Cloud::Logging::Middleware,
73
+ logger: app.config.logger
74
+ end
75
+ end
76
+
77
+ ##
78
+ # Determine whether to use Stackdriver Logging or not.
79
+ #
80
+ # Returns true if valid GCP project_id is provided and underneath API is
81
+ # able to authenticate. Also either Rails needs to be in "production"
82
+ # environment or config.stackdriver.use_logging is explicitly true.
83
+ #
84
+ # @param config The Rails.application.config
85
+ #
86
+ # @return [Boolean]
87
+ #
88
+ def self.use_logging? config
89
+ gcp_config = config.google_cloud
90
+ # Return false if config.stackdriver.use_logging is explicitly false
91
+ return false if gcp_config.key?(:use_logging) &&
92
+ !gcp_config.use_logging
93
+
94
+ # Try authenticate authorize client API. Return false if unable to
95
+ # authorize.
96
+ keyfile = gcp_config.logging.keyfile || gcp_config.keyfile
97
+ begin
98
+ Google::Cloud::Logging::Credentials.credentials_with_scope keyfile
99
+ rescue Exception => e
100
+ warn "Unable to initialize Google::Cloud::Logging due " \
101
+ "to authorization error: #{e.message}"
102
+ return false
103
+ end
104
+
105
+ project_id = gcp_config.logging.project_id || gcp_config.project_id ||
106
+ Google::Cloud::Logging::Project.default_project
107
+ if project_id.to_s.empty?
108
+ warn "Unable to initialize Google::Cloud::Logging with empty " \
109
+ "project_id"
110
+ return false
111
+ end
112
+
113
+ # Otherwise default to true if Rails is running in production or
114
+ # config.stackdriver.use_logging is explicitly true
115
+ Rails.env.production? ||
116
+ (gcp_config.key?(:use_logging) && gcp_config.use_logging)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -30,10 +30,9 @@ module Google
30
30
  # {Google::Cloud::Logging::Project#write_entries}.
31
31
  #
32
32
  # @example
33
- # require "google/cloud"
33
+ # require "google/cloud/logging"
34
34
  #
35
- # gcloud = Google::Cloud.new
36
- # logging = gcloud.logging
35
+ # logging = Google::Cloud::Logging.new
37
36
  # resource = logging.resource "gae_app",
38
37
  # "module_id" => "1",
39
38
  # "version_id" => "20150925t173233"
@@ -31,10 +31,9 @@ module Google
31
31
  # instances, but you can list them with {Project#resource_descriptors}.
32
32
  #
33
33
  # @example
34
- # require "google/cloud"
34
+ # require "google/cloud/logging"
35
35
  #
36
- # gcloud = Google::Cloud.new
37
- # logging = gcloud.logging
36
+ # logging = Google::Cloud::Logging.new
38
37
  # resource_descriptor = logging.resource_descriptors.first
39
38
  # resource_descriptor.type #=> "cloudsql_database"
40
39
  # resource_descriptor.name #=> "Cloud SQL Database"
@@ -93,10 +92,9 @@ module Google
93
92
  # their `database_id`. See {ResourceDescriptor#labels}.
94
93
  #
95
94
  # @example
96
- # require "google/cloud"
95
+ # require "google/cloud/logging"
97
96
  #
98
- # gcloud = Google::Cloud.new
99
- # logging = gcloud.logging
97
+ # logging = Google::Cloud::Logging.new
100
98
  # resource_descriptor = logging.resource_descriptors.first
101
99
  # label_descriptor = resource_descriptor.labels.first
102
100
  # label_descriptor.key #=> "database_id"
@@ -41,10 +41,9 @@ module Google
41
41
  # @return [Boolean]
42
42
  #
43
43
  # @example
44
- # require "google/cloud"
44
+ # require "google/cloud/logging"
45
45
  #
46
- # gcloud = Google::Cloud.new
47
- # logging = gcloud.logging
46
+ # logging = Google::Cloud::Logging.new
48
47
  #
49
48
  # resource_descriptors = logging.resource_descriptors
50
49
  # if resource_descriptors.next?
@@ -61,10 +60,9 @@ module Google
61
60
  # @return [Sink::List]
62
61
  #
63
62
  # @example
64
- # require "google/cloud"
63
+ # require "google/cloud/logging"
65
64
  #
66
- # gcloud = Google::Cloud.new
67
- # logging = gcloud.logging
65
+ # logging = Google::Cloud::Logging.new
68
66
  #
69
67
  # resource_descriptors = logging.resource_descriptors
70
68
  # if resource_descriptors.next?
@@ -100,10 +98,9 @@ module Google
100
98
  # @return [Enumerator]
101
99
  #
102
100
  # @example Iterating each resource descriptor by passing a block:
103
- # require "google/cloud"
101
+ # require "google/cloud/logging"
104
102
  #
105
- # gcloud = Google::Cloud.new
106
- # logging = gcloud.logging
103
+ # logging = Google::Cloud::Logging.new
107
104
  # resource_descriptors = logging.resource_descriptors
108
105
  #
109
106
  # resource_descriptors.all do |rd|
@@ -111,10 +108,9 @@ module Google
111
108
  # end
112
109
  #
113
110
  # @example Using the enumerator by not passing a block:
114
- # require "google/cloud"
111
+ # require "google/cloud/logging"
115
112
  #
116
- # gcloud = Google::Cloud.new
117
- # logging = gcloud.logging
113
+ # logging = Google::Cloud::Logging.new
118
114
  # resource_descriptors = logging.resource_descriptors
119
115
  #
120
116
  # all_types = resource_descriptors.all.map do |rd|
@@ -122,10 +118,9 @@ module Google
122
118
  # end
123
119
  #
124
120
  # @example Limit the number of API calls made:
125
- # require "google/cloud"
121
+ # require "google/cloud/logging"
126
122
  #
127
- # gcloud = Google::Cloud.new
128
- # logging = gcloud.logging
123
+ # logging = Google::Cloud::Logging.new
129
124
  # resource_descriptors = logging.resource_descriptors
130
125
  #
131
126
  # resource_descriptors.all(request_limit: 10) do |rd|
@@ -14,10 +14,8 @@
14
14
 
15
15
 
16
16
  require "google/cloud/errors"
17
- require "google/cloud/core/grpc_backoff"
18
- require "google/logging/v2/logging_pb"
19
- require "google/logging/v2/logging_config_pb"
20
- require "google/logging/v2/logging_metrics_pb"
17
+ require "google/cloud/logging/v2"
18
+ require "google/gax/errors"
21
19
 
22
20
  module Google
23
21
  module Cloud
@@ -26,69 +24,92 @@ module Google
26
24
  # @private Represents the gRPC Logging service, including all the API
27
25
  # methods.
28
26
  class Service
29
- attr_accessor :project, :credentials, :host, :retries, :timeout
27
+ attr_accessor :project, :credentials, :host, :timeout, :client_config
30
28
 
31
29
  ##
32
30
  # Creates a new Service instance.
33
- def initialize project, credentials, host: nil, retries: nil,
34
- timeout: nil
31
+ def initialize project, credentials, host: nil, timeout: nil,
32
+ client_config: nil
35
33
  @project = project
36
34
  @credentials = credentials
37
- @host = host || "logging.googleapis.com"
38
- @retries = retries
35
+ @host = host || V2::LoggingServiceV2Api::SERVICE_ADDRESS
39
36
  @timeout = timeout
37
+ @client_config = client_config || {}
40
38
  end
41
39
 
42
- def creds
40
+ def channel
41
+ require "grpc"
42
+ GRPC::Core::Channel.new host, nil, chan_creds
43
+ end
44
+
45
+ def chan_creds
46
+ return credentials if insecure?
47
+ require "grpc"
43
48
  GRPC::Core::ChannelCredentials.new.compose \
44
49
  GRPC::Core::CallCredentials.new credentials.client.updater_proc
45
50
  end
46
51
 
47
52
  def logging
48
53
  return mocked_logging if mocked_logging
49
- @logging ||= begin
50
- require "google/logging/v2/logging_services_pb"
51
-
52
- Google::Logging::V2::LoggingServiceV2::Stub.new(
53
- host, creds, timeout: timeout)
54
- end
54
+ @logging ||= \
55
+ V2::LoggingServiceV2Api.new(
56
+ service_path: host,
57
+ channel: channel,
58
+ timeout: timeout,
59
+ client_config: client_config,
60
+ app_name: "gcloud-ruby",
61
+ app_version: Google::Cloud::Logging::VERSION)
55
62
  end
56
63
  attr_accessor :mocked_logging
57
64
 
58
65
  def sinks
59
66
  return mocked_sinks if mocked_sinks
60
- @sinks ||= begin
61
- require "google/logging/v2/logging_config_services_pb"
62
-
63
- Google::Logging::V2::ConfigServiceV2::Stub.new(
64
- host, creds, timeout: timeout)
65
- end
67
+ @sinks ||= \
68
+ V2::ConfigServiceV2Api.new(
69
+ service_path: host,
70
+ channel: channel,
71
+ timeout: timeout,
72
+ client_config: client_config,
73
+ app_name: "gcloud-ruby",
74
+ app_version: Google::Cloud::Logging::VERSION)
66
75
  end
67
76
  attr_accessor :mocked_sinks
68
77
 
69
78
  def metrics
70
79
  return mocked_metrics if mocked_metrics
71
- @metrics ||= begin
72
- require "google/logging/v2/logging_metrics_services_pb"
73
-
74
- Google::Logging::V2::MetricsServiceV2::Stub.new(
75
- host, creds, timeout: timeout)
76
- end
80
+ @metrics ||= \
81
+ V2::MetricsServiceV2Api.new(
82
+ service_path: host,
83
+ channel: channel,
84
+ timeout: timeout,
85
+ client_config: client_config,
86
+ app_name: "gcloud-ruby",
87
+ app_version: Google::Cloud::Logging::VERSION)
77
88
  end
78
89
  attr_accessor :mocked_metrics
79
90
 
91
+ def insecure?
92
+ credentials == :this_channel_is_insecure
93
+ end
94
+
80
95
  def list_entries projects: nil, filter: nil, order: nil, token: nil,
81
96
  max: nil
82
- list_params = { project_ids: Array(projects || @project),
83
- filter: filter,
84
- order_by: order,
85
- page_token: token,
86
- page_size: max
87
- }.delete_if { |_, v| v.nil? }
88
97
 
89
- list_req = Google::Logging::V2::ListLogEntriesRequest.new(list_params)
98
+ project_ids = Array(projects || @project)
99
+ call_opts = default_options
100
+ if token
101
+ call_opts = Google::Gax::CallOptions.new(kwargs: default_headers,
102
+ page_token: token)
103
+ end
90
104
 
91
- execute { logging.list_log_entries list_req }
105
+ execute do
106
+ paged_enum = logging.list_log_entries project_ids,
107
+ filter: filter,
108
+ order_by: order,
109
+ page_size: max,
110
+ options: call_opts
111
+ paged_enum.page.response
112
+ end
92
113
  end
93
114
 
94
115
  def write_entries entries, log_name: nil, resource: nil, labels: nil
@@ -99,147 +120,124 @@ module Google
99
120
  resource = resource.to_grpc if resource
100
121
  labels = Hash[labels.map { |k, v| [String(k), String(v)] }] if labels
101
122
 
102
- write_params = { entries: entries,
103
- log_name: log_path(log_name),
104
- resource: resource, labels: labels
105
- }.delete_if { |_, v| v.nil? }
106
-
107
- write_req = Google::Logging::V2::WriteLogEntriesRequest.new(
108
- write_params)
109
-
110
- execute { logging.write_log_entries write_req }
123
+ execute do
124
+ logging.write_log_entries entries,
125
+ log_name: log_path(log_name),
126
+ resource: resource, labels: labels,
127
+ options: default_options
128
+ end
111
129
  end
112
130
 
113
131
  def delete_log name
114
- delete_req = Google::Logging::V2::DeleteLogRequest.new(
115
- log_name: log_path(name)
116
- )
117
-
118
- execute { logging.delete_log delete_req }
132
+ execute do
133
+ logging.delete_log log_path(name), options: default_options
134
+ end
119
135
  end
120
136
 
121
137
  def list_resource_descriptors token: nil, max: nil
122
- list_params = { page_token: token,
123
- page_size: max
124
- }.delete_if { |_, v| v.nil? }
125
-
126
- list_req = \
127
- Google::Logging::V2::ListMonitoredResourceDescriptorsRequest.new(
128
- list_params)
138
+ call_opts = default_options
139
+ if token
140
+ call_opts = Google::Gax::CallOptions.new(kwargs: default_headers,
141
+ page_token: token)
142
+ end
129
143
 
130
- execute { logging.list_monitored_resource_descriptors list_req }
144
+ execute do
145
+ logging.list_monitored_resource_descriptors \
146
+ page_size: max, options: call_opts
147
+ end
131
148
  end
132
149
 
133
150
  def list_sinks token: nil, max: nil
134
- list_params = { parent: project_path,
135
- page_token: token,
136
- page_size: max
137
- }.delete_if { |_, v| v.nil? }
138
-
139
- list_req = Google::Logging::V2::ListSinksRequest.new(list_params)
151
+ call_opts = default_options
152
+ if token
153
+ call_opts = Google::Gax::CallOptions.new(kwargs: default_headers,
154
+ page_token: token)
155
+ end
140
156
 
141
- execute { sinks.list_sinks list_req }
157
+ execute do
158
+ paged_enum = sinks.list_sinks \
159
+ project_path, page_size: max, options: call_opts
160
+ paged_enum.page.response
161
+ end
142
162
  end
143
163
 
144
164
  def create_sink name, destination, filter, version
145
- sink_params = {
146
- name: name, destination: destination,
147
- filter: filter, output_version_format: version
148
- }.delete_if { |_, v| v.nil? }
165
+ sink = Google::Logging::V2::LogSink.new({
166
+ name: name, destination: destination, filter: filter,
167
+ output_version_format: version }.delete_if { |_, v| v.nil? })
149
168
 
150
- create_req = Google::Logging::V2::CreateSinkRequest.new(
151
- parent: project_path,
152
- sink: Google::Logging::V2::LogSink.new(sink_params)
153
- )
154
-
155
- execute { sinks.create_sink create_req }
169
+ execute do
170
+ sinks.create_sink project_path, sink, options: default_options
171
+ end
156
172
  end
157
173
 
158
174
  def get_sink name
159
- get_req = Google::Logging::V2::GetSinkRequest.new(
160
- sink_name: sink_path(name)
161
- )
162
-
163
- execute { sinks.get_sink get_req }
175
+ execute { sinks.get_sink sink_path(name), options: default_options }
164
176
  end
165
177
 
166
178
  def update_sink name, destination, filter, version
167
- sink_params = {
168
- name: name, destination: destination,
169
- filter: filter, output_version_format: version
170
- }.delete_if { |_, v| v.nil? }
179
+ sink = Google::Logging::V2::LogSink.new({
180
+ name: name, destination: destination, filter: filter,
181
+ output_version_format: version }.delete_if { |_, v| v.nil? })
171
182
 
172
- update_req = Google::Logging::V2::UpdateSinkRequest.new(
173
- sink_name: sink_path(name),
174
- sink: Google::Logging::V2::LogSink.new(sink_params)
175
- )
176
-
177
- execute { sinks.update_sink update_req }
183
+ execute do
184
+ sinks.update_sink sink_path(name), sink, options: default_options
185
+ end
178
186
  end
179
187
 
180
188
  def delete_sink name
181
- delete_req = Google::Logging::V2::DeleteSinkRequest.new(
182
- sink_name: sink_path(name)
183
- )
184
-
185
- execute { sinks.delete_sink delete_req }
189
+ execute do
190
+ sinks.delete_sink sink_path(name), options: default_options
191
+ end
186
192
  end
187
193
 
188
194
  def list_metrics token: nil, max: nil
189
- list_params = { parent: project_path,
190
- page_token: token,
191
- page_size: max
192
- }.delete_if { |_, v| v.nil? }
193
-
194
- list_req = Google::Logging::V2::ListLogMetricsRequest.new(list_params)
195
+ call_opts = default_options
196
+ if token
197
+ call_opts = Google::Gax::CallOptions.new(kwargs: default_headers,
198
+ page_token: token)
199
+ end
195
200
 
196
- execute { metrics.list_log_metrics list_req }
201
+ execute do
202
+ paged_enum = metrics.list_log_metrics \
203
+ project_path, page_size: max, options: call_opts
204
+ paged_enum.page.response
205
+ end
197
206
  end
198
207
 
199
208
  def create_metric name, filter, description
200
- metric_params = {
201
- name: name,
202
- description: description,
203
- filter: filter
204
- }.delete_if { |_, v| v.nil? }
205
-
206
- create_req = Google::Logging::V2::CreateLogMetricRequest.new(
207
- parent: project_path,
208
- metric: Google::Logging::V2::LogMetric.new(metric_params)
209
- )
210
-
211
- execute { metrics.create_log_metric create_req }
209
+ metric = Google::Logging::V2::LogMetric.new({
210
+ name: name, description: description,
211
+ filter: filter }.delete_if { |_, v| v.nil? })
212
+
213
+ execute do
214
+ metrics.create_log_metric project_path, metric,
215
+ options: default_options
216
+ end
212
217
  end
213
218
 
214
219
  def get_metric name
215
- get_req = Google::Logging::V2::GetLogMetricRequest.new(
216
- metric_name: metric_path(name)
217
- )
218
-
219
- execute { metrics.get_log_metric get_req }
220
+ execute do
221
+ metrics.get_log_metric metric_path(name), options: default_options
222
+ end
220
223
  end
221
224
 
222
225
  def update_metric name, description, filter
223
- metric_params = {
224
- name: name,
225
- description: description,
226
- filter: filter
227
- }.delete_if { |_, v| v.nil? }
228
-
229
- update_req = Google::Logging::V2::UpdateLogMetricRequest.new(
230
- metric_name: metric_path(name),
231
- metric: Google::Logging::V2::LogMetric.new(metric_params)
232
- )
233
-
234
- execute { metrics.update_log_metric update_req }
226
+ metric = Google::Logging::V2::LogMetric.new({
227
+ name: name, description: description,
228
+ filter: filter }.delete_if { |_, v| v.nil? })
229
+
230
+ execute do
231
+ metrics.update_log_metric metric_path(name), metric,
232
+ options: default_options
233
+ end
235
234
  end
236
235
 
237
236
  def delete_metric name
238
- delete_req = Google::Logging::V2::DeleteLogMetricRequest.new(
239
- metric_name: metric_path(name)
240
- )
241
-
242
- execute { metrics.delete_log_metric delete_req }
237
+ execute do
238
+ metrics.delete_log_metric metric_path(name),
239
+ options: default_options
240
+ end
243
241
  end
244
242
 
245
243
  def inspect
@@ -269,12 +267,19 @@ module Google
269
267
  "#{project_path}/metrics/#{metric_name}"
270
268
  end
271
269
 
270
+ def default_headers
271
+ { "google-cloud-resource-prefix" => "projects/#{@project}" }
272
+ end
273
+
274
+ def default_options
275
+ Google::Gax::CallOptions.new kwargs: default_headers
276
+ end
277
+
272
278
  def execute
273
- Google::Cloud::Core::GrpcBackoff.new(retries: retries).execute do
274
- yield
275
- end
276
- rescue GRPC::BadStatus => e
277
- raise Google::Cloud::Error.from_error(e)
279
+ yield
280
+ rescue Google::Gax::GaxError => e
281
+ # GaxError wraps BadStatus, but exposes it as #cause
282
+ raise Google::Cloud::Error.from_error(e.cause)
278
283
  end
279
284
  end
280
285
  end