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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

119 statements  

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 isinstance(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 self._handlers = set() 

153 

154 @property 

155 def logging_api(self): 

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

157 

158 See 

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

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

161 """ 

162 if self._logging_api is None: 

163 if self._use_grpc: 

164 self._logging_api = _gapic.make_logging_api(self) 

165 else: 

166 self._logging_api = JSONLoggingAPI(self) 

167 return self._logging_api 

168 

169 @property 

170 def sinks_api(self): 

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

172 

173 See 

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

175 """ 

176 if self._sinks_api is None: 

177 if self._use_grpc: 

178 self._sinks_api = _gapic.make_sinks_api(self) 

179 else: 

180 self._sinks_api = JSONSinksAPI(self) 

181 return self._sinks_api 

182 

183 @property 

184 def metrics_api(self): 

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

186 

187 See 

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

189 """ 

190 if self._metrics_api is None: 

191 if self._use_grpc: 

192 self._metrics_api = _gapic.make_metrics_api(self) 

193 else: 

194 self._metrics_api = JSONMetricsAPI(self) 

195 return self._metrics_api 

196 

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

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

199 

200 Args: 

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

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

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

204 be inferred from the environment. 

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

206 via this logger. 

207 

208 Returns: 

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

210 """ 

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

212 

213 def list_entries( 

214 self, 

215 *, 

216 resource_names=None, 

217 filter_=None, 

218 order_by=None, 

219 max_results=None, 

220 page_size=None, 

221 page_token=None, 

222 ): 

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

224 

225 Args: 

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

227 from which to retrieve log entries: 

228 

229 :: 

230 

231 "projects/[PROJECT_ID]" 

232 "organizations/[ORGANIZATION_ID]" 

233 "billingAccounts/[BILLING_ACCOUNT_ID]" 

234 "folders/[FOLDER_ID]" 

235 

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

237 

238 filter_ (str): a filter expression. See 

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

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

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

242 max_results (Optional[int]): 

243 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

250 

251 Returns: 

252 Generator[~logging_v2.LogEntry] 

253 """ 

254 if resource_names is None: 

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

256 filter_ = _add_defaults_to_filter(filter_) 

257 

258 return self.logging_api.list_entries( 

259 resource_names=resource_names, 

260 filter_=filter_, 

261 order_by=order_by, 

262 max_results=max_results, 

263 page_size=page_size, 

264 page_token=page_token, 

265 ) 

266 

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

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

269 

270 Args: 

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

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

273 defining the entries exported by the sink. If not 

274 passed, the instance should already exist, to be 

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

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

277 the sink. If not passed, the instance should 

278 already exist, to be refreshed via 

279 :meth:`Sink.reload`. 

280 

281 Returns: 

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

283 """ 

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

285 

286 def list_sinks( 

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

288 ): 

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

290 

291 See 

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

293 

294 Args: 

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

296 

297 :: 

298 

299 "projects/[PROJECT_ID]" 

300 "organizations/[ORGANIZATION_ID]" 

301 "billingAccounts/[BILLING_ACCOUNT_ID]" 

302 "folders/[FOLDER_ID]". 

303 

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

305 max_results (Optional[int]): 

306 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

313 

314 Returns: 

315 Generator[~logging_v2.Sink] 

316 """ 

317 if parent is None: 

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

319 return self.sinks_api.list_sinks( 

320 parent=parent, 

321 max_results=max_results, 

322 page_size=page_size, 

323 page_token=page_token, 

324 ) 

325 

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

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

328 

329 Args: 

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

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

332 entries tracked by the metric. If not 

333 passed, the instance should already exist, to be 

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

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

336 If not passed, the instance should already exist, 

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

338 

339 Returns: 

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

341 """ 

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

343 

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

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

346 

347 See 

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

349 

350 Args: 

351 max_results (Optional[int]): 

352 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

359 

360 Returns: 

361 Generator[logging_v2.Metric] 

362 """ 

363 return self.metrics_api.list_metrics( 

364 self.project, 

365 max_results=max_results, 

366 page_size=page_size, 

367 page_token=page_token, 

368 ) 

369 

370 def get_default_handler(self, **kw): 

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

372 

373 Args: 

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

375 

376 Returns: 

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

378 """ 

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

380 

381 if isinstance(monitored_resource, Resource): 

382 if monitored_resource.type == _GAE_RESOURCE_TYPE: 

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

384 elif monitored_resource.type == _GKE_RESOURCE_TYPE: 

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

386 elif monitored_resource.type == _GCF_RESOURCE_TYPE: 

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

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

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

390 elif monitored_resource.type == _RUN_RESOURCE_TYPE: 

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

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

393 

394 def setup_logging( 

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

396 ): 

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

398 

399 This method uses the default log handler, obtained by 

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

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

402 loggers, will report to Cloud Logging. 

403 

404 Args: 

405 log_level (Optional[int]): The logging level threshold of the attached logger, 

406 as set by the :meth:`logging.Logger.setLevel` method. Defaults to 

407 :const:`logging.INFO`. 

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

409 handler to. This will always include the 

410 loggers in the path of the logging client 

411 itself. 

412 Returns: 

413 dict: keyword args passed to handler constructor 

414 """ 

415 handler = self.get_default_handler(**kw) 

416 self._handlers.add(handler) 

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

418 

419 def flush_handlers(self): 

420 """Flushes all Python log handlers associated with this Client.""" 

421 

422 for handler in self._handlers: 

423 handler.flush() 

424 

425 def close(self): 

426 """Closes the Client and all handlers associated with this Client.""" 

427 super(Client, self).close() 

428 for handler in self._handlers: 

429 handler.close()