Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/cloud/logging_v2/client.py: 48%

108 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 07:30 +0000

1# Copyright 2016 Google LLC 

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"""Client for interacting with the Google Cloud Logging API.""" 

16 

17import logging 

18import os 

19import sys 

20 

21 

22import google.api_core.client_options 

23from google.cloud.client import ClientWithProject 

24from google.cloud.environment_vars import DISABLE_GRPC 

25from google.cloud.logging_v2._helpers import _add_defaults_to_filter 

26from google.cloud.logging_v2._http import Connection 

27from google.cloud.logging_v2._http import _LoggingAPI as JSONLoggingAPI 

28from google.cloud.logging_v2._http import _MetricsAPI as JSONMetricsAPI 

29from google.cloud.logging_v2._http import _SinksAPI as JSONSinksAPI 

30from google.cloud.logging_v2.handlers import CloudLoggingHandler 

31from google.cloud.logging_v2.handlers import StructuredLogHandler 

32from google.cloud.logging_v2.handlers import setup_logging 

33from google.cloud.logging_v2.handlers.handlers import EXCLUDED_LOGGER_DEFAULTS 

34from google.cloud.logging_v2.resource import Resource 

35from google.cloud.logging_v2.handlers._monitored_resources import detect_resource 

36 

37 

38from google.cloud.logging_v2.logger import Logger 

39from google.cloud.logging_v2.metric import Metric 

40from google.cloud.logging_v2.sink import Sink 

41 

42 

43_DISABLE_GRPC = os.getenv(DISABLE_GRPC, False) 

44_HAVE_GRPC = False 

45 

46try: 

47 if not _DISABLE_GRPC: 

48 # only import if DISABLE_GRPC is not set 

49 from google.cloud.logging_v2 import _gapic 

50 

51 _HAVE_GRPC = True 

52except ImportError: # pragma: NO COVER 

53 # could not import gapic library. Fall back to HTTP mode 

54 _HAVE_GRPC = False 

55 _gapic = None 

56 

57_USE_GRPC = _HAVE_GRPC and not _DISABLE_GRPC 

58 

59_GAE_RESOURCE_TYPE = "gae_app" 

60_GKE_RESOURCE_TYPE = "k8s_container" 

61_GCF_RESOURCE_TYPE = "cloud_function" 

62_RUN_RESOURCE_TYPE = "cloud_run_revision" 

63 

64 

65class Client(ClientWithProject): 

66 """Client to bundle configuration needed for API requests.""" 

67 

68 _logging_api = None 

69 _sinks_api = None 

70 _metrics_api = None 

71 

72 SCOPE = ( 

73 "https://www.googleapis.com/auth/logging.read", 

74 "https://www.googleapis.com/auth/logging.write", 

75 "https://www.googleapis.com/auth/logging.admin", 

76 "https://www.googleapis.com/auth/cloud-platform", 

77 ) 

78 """The scopes required for authenticating as a Logging consumer.""" 

79 

80 def __init__( 

81 self, 

82 *, 

83 project=None, 

84 credentials=None, 

85 _http=None, 

86 _use_grpc=None, 

87 client_info=None, 

88 client_options=None, 

89 ): 

90 """ 

91 Args: 

92 project (Optional[str]): the project which the client acts on behalf of. 

93 If not passed, falls back to the default inferred 

94 from the environment. 

95 credentials (Optional[google.auth.credentials.Credentials]): 

96 Thehe OAuth2 Credentials to use for this 

97 client. If not passed (and if no ``_http`` object is 

98 passed), falls back to the default inferred from the 

99 environment. 

100 _http (Optional[requests.Session]): HTTP object to make requests. 

101 Can be any object that defines ``request()`` with the same interface as 

102 :meth:`requests.Session.request`. If not passed, an 

103 ``_http`` object is created that is bound to the 

104 ``credentials`` for the current object. 

105 This parameter should be considered private, and could 

106 change in the future. 

107 _use_grpc (Optional[bool]): Explicitly specifies whether 

108 to use the gRPC transport or HTTP. If unset, 

109 falls back to the ``GOOGLE_CLOUD_DISABLE_GRPC`` 

110 environment variable 

111 This parameter should be considered private, and could 

112 change in the future. 

113 client_info (Optional[Union[google.api_core.client_info.ClientInfo, google.api_core.gapic_v1.client_info.ClientInfo]]): 

114 The client info used to send a user-agent string along with API 

115 requests. If ``None``, then default info will be used. Generally, 

116 you only need to set this if you're developing your own library 

117 or partner tool. 

118 client_options (Optional[Union[dict, google.api_core.client_options.ClientOptions]]): 

119 Client options used to set user options 

120 on the client. API Endpoint should be set through client_options. 

121 """ 

122 super(Client, self).__init__( 

123 project=project, 

124 credentials=credentials, 

125 _http=_http, 

126 client_options=client_options, 

127 ) 

128 

129 kw_args = {"client_info": client_info} 

130 if client_options: 

131 if type(client_options) == dict: 

132 client_options = google.api_core.client_options.from_dict( 

133 client_options 

134 ) 

135 if client_options.api_endpoint: 

136 api_endpoint = client_options.api_endpoint 

137 kw_args["api_endpoint"] = api_endpoint 

138 

139 self._connection = Connection(self, **kw_args) 

140 if client_info is None: 

141 # if client info not passed in, use the discovered 

142 # client info from _connection object 

143 client_info = self._connection._client_info 

144 

145 self._client_info = client_info 

146 self._client_options = client_options 

147 if _use_grpc is None: 

148 self._use_grpc = _USE_GRPC 

149 else: 

150 self._use_grpc = _use_grpc 

151 

152 @property 

153 def logging_api(self): 

154 """Helper for logging-related API calls. 

155 

156 See 

157 https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries 

158 https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs 

159 """ 

160 if self._logging_api is None: 

161 if self._use_grpc: 

162 self._logging_api = _gapic.make_logging_api(self) 

163 else: 

164 self._logging_api = JSONLoggingAPI(self) 

165 return self._logging_api 

166 

167 @property 

168 def sinks_api(self): 

169 """Helper for log sink-related API calls. 

170 

171 See 

172 https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks 

173 """ 

174 if self._sinks_api is None: 

175 if self._use_grpc: 

176 self._sinks_api = _gapic.make_sinks_api(self) 

177 else: 

178 self._sinks_api = JSONSinksAPI(self) 

179 return self._sinks_api 

180 

181 @property 

182 def metrics_api(self): 

183 """Helper for log metric-related API calls. 

184 

185 See 

186 https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics 

187 """ 

188 if self._metrics_api is None: 

189 if self._use_grpc: 

190 self._metrics_api = _gapic.make_metrics_api(self) 

191 else: 

192 self._metrics_api = JSONMetricsAPI(self) 

193 return self._metrics_api 

194 

195 def logger(self, name, *, labels=None, resource=None): 

196 """Creates a logger bound to the current client. 

197 

198 Args: 

199 name (str): The name of the logger to be constructed. 

200 resource (Optional[~logging_v2.Resource]): a monitored resource object 

201 representing the resource the code was run on. If not given, will 

202 be inferred from the environment. 

203 labels (Optional[dict]): Mapping of default labels for entries written 

204 via this logger. 

205 

206 Returns: 

207 ~logging_v2.logger.Logger: Logger created with the current client. 

208 """ 

209 return Logger(name, client=self, labels=labels, resource=resource) 

210 

211 def list_entries( 

212 self, 

213 *, 

214 resource_names=None, 

215 filter_=None, 

216 order_by=None, 

217 max_results=None, 

218 page_size=None, 

219 page_token=None, 

220 ): 

221 """Return a generator of log entry resources. 

222 

223 Args: 

224 resource_names (Sequence[str]): Names of one or more parent resources 

225 from which to retrieve log entries: 

226 

227 :: 

228 

229 "projects/[PROJECT_ID]" 

230 "organizations/[ORGANIZATION_ID]" 

231 "billingAccounts/[BILLING_ACCOUNT_ID]" 

232 "folders/[FOLDER_ID]" 

233 

234 If not passed, defaults to the project bound to the API's client. 

235 

236 filter_ (str): a filter expression. See 

237 https://cloud.google.com/logging/docs/view/advanced_filters 

238 order_by (str) One of :data:`~logging_v2.ASCENDING` 

239 or :data:`~logging_v2.DESCENDING`. 

240 max_results (Optional[int]): 

241 Optional. The maximum number of entries to return. 

242 Non-positive values are treated as 0. If None, uses API defaults. 

243 page_size (int): number of entries to fetch in each API call. Although 

244 requests are paged internally, logs are returned by the generator 

245 one at a time. If not passed, defaults to a value set by the API. 

246 page_token (str): opaque marker for the starting "page" of entries. If not 

247 passed, the API will return the first page of entries. 

248 

249 Returns: 

250 Generator[~logging_v2.LogEntry] 

251 """ 

252 if resource_names is None: 

253 resource_names = [f"projects/{self.project}"] 

254 filter_ = _add_defaults_to_filter(filter_) 

255 

256 return self.logging_api.list_entries( 

257 resource_names=resource_names, 

258 filter_=filter_, 

259 order_by=order_by, 

260 max_results=max_results, 

261 page_size=page_size, 

262 page_token=page_token, 

263 ) 

264 

265 def sink(self, name, *, filter_=None, destination=None): 

266 """Creates a sink bound to the current client. 

267 

268 Args: 

269 name (str): the name of the sink to be constructed. 

270 filter_ (Optional[str]): the advanced logs filter expression 

271 defining the entries exported by the sink. If not 

272 passed, the instance should already exist, to be 

273 refreshed via :meth:`Sink.reload`. 

274 destination (str): destination URI for the entries exported by 

275 the sink. If not passed, the instance should 

276 already exist, to be refreshed via 

277 :meth:`Sink.reload`. 

278 

279 Returns: 

280 ~logging_v2.sink.Sink: Sink created with the current client. 

281 """ 

282 return Sink(name, filter_=filter_, destination=destination, client=self) 

283 

284 def list_sinks( 

285 self, *, parent=None, max_results=None, page_size=None, page_token=None 

286 ): 

287 """List sinks for the a parent resource. 

288 

289 See 

290 https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/list 

291 

292 Args: 

293 parent (Optional[str]): The parent resource whose sinks are to be listed: 

294 

295 :: 

296 

297 "projects/[PROJECT_ID]" 

298 "organizations/[ORGANIZATION_ID]" 

299 "billingAccounts/[BILLING_ACCOUNT_ID]" 

300 "folders/[FOLDER_ID]". 

301 

302 If not passed, defaults to the project bound to the API's client. 

303 max_results (Optional[int]): 

304 Optional. The maximum number of entries to return. 

305 Non-positive values are treated as 0. If None, uses API defaults. 

306 page_size (int): number of entries to fetch in each API call. Although 

307 requests are paged internally, logs are returned by the generator 

308 one at a time. If not passed, defaults to a value set by the API. 

309 page_token (str): opaque marker for the starting "page" of entries. If not 

310 passed, the API will return the first page of entries. 

311 

312 Returns: 

313 Generator[~logging_v2.Sink] 

314 """ 

315 if parent is None: 

316 parent = f"projects/{self.project}" 

317 return self.sinks_api.list_sinks( 

318 parent=parent, 

319 max_results=max_results, 

320 page_size=page_size, 

321 page_token=page_token, 

322 ) 

323 

324 def metric(self, name, *, filter_=None, description=""): 

325 """Creates a metric bound to the current client. 

326 

327 Args: 

328 name (str): The name of the metric to be constructed. 

329 filter_(Optional[str]): The advanced logs filter expression defining the 

330 entries tracked by the metric. If not 

331 passed, the instance should already exist, to be 

332 refreshed via :meth:`Metric.reload`. 

333 description (Optional[str]): The description of the metric to be constructed. 

334 If not passed, the instance should already exist, 

335 to be refreshed via :meth:`Metric.reload`. 

336 

337 Returns: 

338 ~logging_v2.metric.Metric: Metric created with the current client. 

339 """ 

340 return Metric(name, filter_=filter_, client=self, description=description) 

341 

342 def list_metrics(self, *, max_results=None, page_size=None, page_token=None): 

343 """List metrics for the project associated with this client. 

344 

345 See 

346 https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/list 

347 

348 Args: 

349 max_results (Optional[int]): 

350 Optional. The maximum number of entries to return. 

351 Non-positive values are treated as 0. If None, uses API defaults. 

352 page_size (int): number of entries to fetch in each API call. Although 

353 requests are paged internally, logs are returned by the generator 

354 one at a time. If not passed, defaults to a value set by the API. 

355 page_token (str): opaque marker for the starting "page" of entries. If not 

356 passed, the API will return the first page of entries. 

357 

358 Returns: 

359 Generator[logging_v2.Metric] 

360 """ 

361 return self.metrics_api.list_metrics( 

362 self.project, 

363 max_results=max_results, 

364 page_size=page_size, 

365 page_token=page_token, 

366 ) 

367 

368 def get_default_handler(self, **kw): 

369 """Return the default logging handler based on the local environment. 

370 

371 Args: 

372 kw (dict): keyword args passed to handler constructor 

373 

374 Returns: 

375 logging.Handler: The default log handler based on the environment 

376 """ 

377 monitored_resource = kw.pop("resource", detect_resource(self.project)) 

378 

379 if isinstance(monitored_resource, Resource): 

380 if monitored_resource.type == _GAE_RESOURCE_TYPE: 

381 return CloudLoggingHandler(self, resource=monitored_resource, **kw) 

382 elif monitored_resource.type == _GKE_RESOURCE_TYPE: 

383 return StructuredLogHandler(**kw, project_id=self.project) 

384 elif monitored_resource.type == _GCF_RESOURCE_TYPE: 

385 # __stdout__ stream required to support structured logging on Python 3.7 

386 kw["stream"] = kw.get("stream", sys.__stdout__) 

387 return StructuredLogHandler(**kw, project_id=self.project) 

388 elif monitored_resource.type == _RUN_RESOURCE_TYPE: 

389 return StructuredLogHandler(**kw, project_id=self.project) 

390 return CloudLoggingHandler(self, resource=monitored_resource, **kw) 

391 

392 def setup_logging( 

393 self, *, log_level=logging.INFO, excluded_loggers=EXCLUDED_LOGGER_DEFAULTS, **kw 

394 ): 

395 """Attach default Cloud Logging handler to the root logger. 

396 

397 This method uses the default log handler, obtained by 

398 :meth:`~get_default_handler`, and attaches it to the root Python 

399 logger, so that a call such as ``logging.warn``, as well as all child 

400 loggers, will report to Cloud Logging. 

401 

402 Args: 

403 log_level (Optional[int]): Python logging log level. Defaults to 

404 :const:`logging.INFO`. 

405 excluded_loggers (Optional[Tuple[str]]): The loggers to not attach the 

406 handler to. This will always include the 

407 loggers in the path of the logging client 

408 itself. 

409 Returns: 

410 dict: keyword args passed to handler constructor 

411 """ 

412 handler = self.get_default_handler(**kw) 

413 setup_logging(handler, log_level=log_level, excluded_loggers=excluded_loggers)