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

116 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:45 +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"""Interact with Cloud Logging via JSON-over-HTTP.""" 

16 

17import functools 

18 

19from google.api_core import page_iterator 

20from google.cloud import _http 

21 

22from google.cloud.logging_v2 import __version__ 

23from google.cloud.logging_v2._helpers import entry_from_resource 

24from google.cloud.logging_v2.sink import Sink 

25from google.cloud.logging_v2.metric import Metric 

26 

27 

28class Connection(_http.JSONConnection): 

29 

30 DEFAULT_API_ENDPOINT = "https://logging.googleapis.com" 

31 

32 def __init__(self, client, *, client_info=None, api_endpoint=DEFAULT_API_ENDPOINT): 

33 """A connection to Google Cloud Logging via the JSON REST API. 

34 

35 Args: 

36 client (google.cloud.logging_v2.cliet.Client): 

37 The client that owns the current connection. 

38 client_info (Optional[google.api_core.client_info.ClientInfo]): 

39 Instance used to generate user agent. 

40 client_options (Optional[google.api_core.client_options.ClientOptions]): 

41 Client options used to set user options 

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

43 """ 

44 super(Connection, self).__init__(client, client_info) 

45 self.API_BASE_URL = api_endpoint 

46 self._client_info.gapic_version = __version__ 

47 self._client_info.client_library_version = __version__ 

48 

49 API_VERSION = "v2" 

50 """The version of the API, used in building the API call's URL.""" 

51 

52 API_URL_TEMPLATE = "{api_base_url}/{api_version}{path}" 

53 """A template for the URL of a particular API call.""" 

54 

55 

56class _LoggingAPI(object): 

57 """Helper mapping logging-related APIs. 

58 

59 See 

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

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

62 

63 :type client: :class:`~google.cloud.logging.client.Client` 

64 :param client: The client used to make API requests. 

65 """ 

66 

67 def __init__(self, client): 

68 self._client = client 

69 self.api_request = client._connection.api_request 

70 

71 def list_entries( 

72 self, 

73 resource_names, 

74 *, 

75 filter_=None, 

76 order_by=None, 

77 max_results=None, 

78 page_size=None, 

79 page_token=None, 

80 ): 

81 """Return a page of log entry resources. 

82 

83 Args: 

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

85 from which to retrieve log entries: 

86 

87 :: 

88 

89 "projects/[PROJECT_ID]" 

90 "organizations/[ORGANIZATION_ID]" 

91 "billingAccounts/[BILLING_ACCOUNT_ID]" 

92 "folders/[FOLDER_ID]" 

93 

94 filter_ (str): a filter expression. See 

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

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

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

98 max_results (Optional[int]): 

99 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

106 Returns: 

107 Generator[~logging_v2.LogEntry] 

108 """ 

109 extra_params = {"resourceNames": resource_names} 

110 

111 if filter_ is not None: 

112 extra_params["filter"] = filter_ 

113 

114 if order_by is not None: 

115 extra_params["orderBy"] = order_by 

116 

117 if page_size is not None: 

118 extra_params["pageSize"] = page_size 

119 

120 path = "/entries:list" 

121 # We attach a mutable loggers dictionary so that as Logger 

122 # objects are created by entry_from_resource, they can be 

123 # re-used by other log entries from the same logger. 

124 loggers = {} 

125 item_to_value = functools.partial(_item_to_entry, loggers=loggers) 

126 iterator = page_iterator.HTTPIterator( 

127 client=self._client, 

128 api_request=self._client._connection.api_request, 

129 path=path, 

130 item_to_value=item_to_value, 

131 items_key="entries", 

132 page_token=page_token, 

133 extra_params=extra_params, 

134 ) 

135 # This method uses POST to make a read-only request. 

136 iterator._HTTP_METHOD = "POST" 

137 

138 return _entries_pager(iterator, max_results) 

139 

140 def write_entries( 

141 self, 

142 entries, 

143 *, 

144 logger_name=None, 

145 resource=None, 

146 labels=None, 

147 partial_success=True, 

148 dry_run=False, 

149 ): 

150 """Log an entry resource via a POST request 

151 

152 See 

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

154 

155 Args: 

156 entries (Sequence[Mapping[str, ...]]): sequence of mappings representing 

157 the log entry resources to log. 

158 logger_name (Optional[str]): name of default logger to which to log the entries; 

159 individual entries may override. 

160 resource(Optional[Mapping[str, ...]]): default resource to associate with entries; 

161 individual entries may override. 

162 labels (Optional[Mapping[str, ...]]): default labels to associate with entries; 

163 individual entries may override. 

164 partial_success (Optional[bool]): Whether valid entries should be written even if 

165 some other entries fail due to INVALID_ARGUMENT or 

166 PERMISSION_DENIED errors. If any entry is not written, then 

167 the response status is the error associated with one of the 

168 failed entries and the response includes error details keyed 

169 by the entries' zero-based index in the ``entries.write`` 

170 method. 

171 dry_run (Optional[bool]): 

172 If true, the request should expect normal response, 

173 but the entries won't be persisted nor exported. 

174 Useful for checking whether the logging API endpoints are working 

175 properly before sending valuable data. 

176 """ 

177 data = { 

178 "entries": list(entries), 

179 "partialSuccess": partial_success, 

180 "dry_run": dry_run, 

181 } 

182 

183 if logger_name is not None: 

184 data["logName"] = logger_name 

185 

186 if resource is not None: 

187 data["resource"] = resource 

188 

189 if labels is not None: 

190 data["labels"] = labels 

191 

192 self.api_request(method="POST", path="/entries:write", data=data) 

193 

194 def logger_delete(self, logger_name): 

195 """Delete all entries in a logger. 

196 

197 Args: 

198 logger_name (str): The resource name of the log to delete: 

199 

200 :: 

201 

202 "projects/[PROJECT_ID]/logs/[LOG_ID]" 

203 "organizations/[ORGANIZATION_ID]/logs/[LOG_ID]" 

204 "billingAccounts/[BILLING_ACCOUNT_ID]/logs/[LOG_ID]" 

205 "folders/[FOLDER_ID]/logs/[LOG_ID]" 

206 

207 ``[LOG_ID]`` must be URL-encoded. For example, 

208 ``"projects/my-project-id/logs/syslog"``, 

209 ``"organizations/1234567890/logs/cloudresourcemanager.googleapis.com%2Factivity"``. 

210 """ 

211 path = f"/{logger_name}" 

212 self.api_request(method="DELETE", path=path) 

213 

214 

215class _SinksAPI(object): 

216 """Helper mapping sink-related APIs. 

217 

218 See 

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

220 """ 

221 

222 def __init__(self, client): 

223 self._client = client 

224 self.api_request = client._connection.api_request 

225 

226 def list_sinks(self, parent, *, max_results=None, page_size=None, page_token=None): 

227 """List sinks for the parent resource. 

228 

229 See 

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

231 

232 Args: 

233 parent (str): The parent resource whose sinks are to be listed: 

234 

235 :: 

236 

237 "projects/[PROJECT_ID]" 

238 "organizations/[ORGANIZATION_ID]" 

239 "billingAccounts/[BILLING_ACCOUNT_ID]" 

240 "folders/[FOLDER_ID]". 

241 max_results (Optional[int]): 

242 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

249 

250 Returns: 

251 Generator[~logging_v2.Sink] 

252 """ 

253 extra_params = {} 

254 

255 if page_size is not None: 

256 extra_params["pageSize"] = page_size 

257 

258 path = f"/{parent}/sinks" 

259 iterator = page_iterator.HTTPIterator( 

260 client=self._client, 

261 api_request=self._client._connection.api_request, 

262 path=path, 

263 item_to_value=_item_to_sink, 

264 items_key="sinks", 

265 page_token=page_token, 

266 extra_params=extra_params, 

267 ) 

268 

269 return _entries_pager(iterator, max_results) 

270 

271 def sink_create( 

272 self, parent, sink_name, filter_, destination, *, unique_writer_identity=False 

273 ): 

274 """Create a sink resource. 

275 

276 See 

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

278 

279 Args: 

280 parent(str): The resource in which to create the sink: 

281 

282 :: 

283 

284 "projects/[PROJECT_ID]" 

285 "organizations/[ORGANIZATION_ID]" 

286 "billingAccounts/[BILLING_ACCOUNT_ID]" 

287 "folders/[FOLDER_ID]". 

288 sink_name (str): The name of the sink. 

289 filter_ (str): The advanced logs filter expression defining the 

290 entries exported by the sink. 

291 destination (str): Destination URI for the entries exported by 

292 the sink. 

293 unique_writer_identity (Optional[bool]): determines the kind of 

294 IAM identity returned as writer_identity in the new sink. 

295 

296 Returns: 

297 dict: The sink resource returned from the API. 

298 """ 

299 target = f"/{parent}/sinks" 

300 data = {"name": sink_name, "filter": filter_, "destination": destination} 

301 query_params = {"uniqueWriterIdentity": unique_writer_identity} 

302 return self.api_request( 

303 method="POST", path=target, data=data, query_params=query_params 

304 ) 

305 

306 def sink_get(self, sink_name): 

307 """Retrieve a sink resource. 

308 

309 Args: 

310 sink_name (str): The resource name of the sink: 

311 

312 :: 

313 

314 "projects/[PROJECT_ID]/sinks/[SINK_ID]" 

315 "organizations/[ORGANIZATION_ID]/sinks/[SINK_ID]" 

316 "billingAccounts/[BILLING_ACCOUNT_ID]/sinks/[SINK_ID]" 

317 "folders/[FOLDER_ID]/sinks/[SINK_ID]" 

318 

319 Returns: 

320 dict: The JSON sink object returned from the API. 

321 """ 

322 target = f"/{sink_name}" 

323 return self.api_request(method="GET", path=target) 

324 

325 def sink_update( 

326 self, sink_name, filter_, destination, *, unique_writer_identity=False 

327 ): 

328 """Update a sink resource. 

329 

330 Args: 

331 sink_name (str): Required. The resource name of the sink: 

332 

333 :: 

334 

335 "projects/[PROJECT_ID]/sinks/[SINK_ID]" 

336 "organizations/[ORGANIZATION_ID]/sinks/[SINK_ID]" 

337 "billingAccounts/[BILLING_ACCOUNT_ID]/sinks/[SINK_ID]" 

338 "folders/[FOLDER_ID]/sinks/[SINK_ID]" 

339 filter_ (str): The advanced logs filter expression defining the 

340 entries exported by the sink. 

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

342 the sink. 

343 unique_writer_identity (Optional[bool]): determines the kind of 

344 IAM identity returned as writer_identity in the new sink. 

345 

346 

347 Returns: 

348 dict: The returned (updated) resource. 

349 """ 

350 target = f"/{sink_name}" 

351 name = sink_name.split("/")[-1] # parse name out of full resoure name 

352 data = {"name": name, "filter": filter_, "destination": destination} 

353 query_params = {"uniqueWriterIdentity": unique_writer_identity} 

354 return self.api_request( 

355 method="PUT", path=target, query_params=query_params, data=data 

356 ) 

357 

358 def sink_delete(self, sink_name): 

359 """Delete a sink resource. 

360 

361 Args: 

362 sink_name (str): Required. The full resource name of the sink to delete, 

363 including the parent resource and the sink identifier: 

364 

365 :: 

366 

367 "projects/[PROJECT_ID]/sinks/[SINK_ID]" 

368 "organizations/[ORGANIZATION_ID]/sinks/[SINK_ID]" 

369 "billingAccounts/[BILLING_ACCOUNT_ID]/sinks/[SINK_ID]" 

370 "folders/[FOLDER_ID]/sinks/[SINK_ID]" 

371 

372 Example: ``"projects/my-project-id/sinks/my-sink-id"``. 

373 """ 

374 target = f"/{sink_name}" 

375 self.api_request(method="DELETE", path=target) 

376 

377 

378class _MetricsAPI(object): 

379 """Helper mapping sink-related APIs.""" 

380 

381 def __init__(self, client): 

382 self._client = client 

383 self.api_request = client._connection.api_request 

384 

385 def list_metrics( 

386 self, project, *, max_results=None, page_size=None, page_token=None 

387 ): 

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

389 

390 See 

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

392 

393 Args: 

394 max_results (Optional[int]): 

395 Optional. The maximum number of entries to return. 

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

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

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

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

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

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

402 

403 Returns: 

404 Generator[logging_v2.Metric] 

405 

406 """ 

407 extra_params = {} 

408 

409 if page_size is not None: 

410 extra_params["pageSize"] = page_size 

411 

412 path = f"/projects/{project}/metrics" 

413 iterator = page_iterator.HTTPIterator( 

414 client=self._client, 

415 api_request=self._client._connection.api_request, 

416 path=path, 

417 item_to_value=_item_to_metric, 

418 items_key="metrics", 

419 page_token=page_token, 

420 extra_params=extra_params, 

421 ) 

422 return _entries_pager(iterator, max_results) 

423 

424 def metric_create(self, project, metric_name, filter_, description): 

425 """Create a metric resource. 

426 

427 See 

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

429 

430 Args: 

431 project (str): ID of the project in which to create the metric. 

432 metric_name (str): The name of the metric 

433 filter_ (str): The advanced logs filter expression defining the 

434 entries exported by the metric. 

435 description (str): description of the metric. 

436 """ 

437 target = f"/projects/{project}/metrics" 

438 data = {"name": metric_name, "filter": filter_, "description": description} 

439 self.api_request(method="POST", path=target, data=data) 

440 

441 def metric_get(self, project, metric_name): 

442 """Retrieve a metric resource. 

443 

444 Args: 

445 project (str): ID of the project containing the metric. 

446 metric_name (str): The name of the metric 

447 

448 Returns: 

449 dict: The JSON metric object returned from the API. 

450 """ 

451 target = f"/projects/{project}/metrics/{metric_name}" 

452 return self.api_request(method="GET", path=target) 

453 

454 def metric_update(self, project, metric_name, filter_, description): 

455 """Update a metric resource. 

456 

457 See 

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

459 

460 Args: 

461 project (str): ID of the project containing the metric. 

462 metric_name (str): the name of the metric 

463 filter_ (str): the advanced logs filter expression defining the 

464 entries exported by the metric. 

465 description (str): description of the metric. 

466 

467 Returns: 

468 dict: The returned (updated) resource. 

469 """ 

470 target = f"/projects/{project}/metrics/{metric_name}" 

471 data = {"name": metric_name, "filter": filter_, "description": description} 

472 return self.api_request(method="PUT", path=target, data=data) 

473 

474 def metric_delete(self, project, metric_name): 

475 """Delete a metric resource. 

476 

477 Args: 

478 project (str): ID of the project containing the metric. 

479 metric_name (str): The name of the metric 

480 """ 

481 target = f"/projects/{project}/metrics/{metric_name}" 

482 self.api_request(method="DELETE", path=target) 

483 

484 

485def _entries_pager(page_iter, max_results=None): 

486 if max_results is not None and max_results < 0: 

487 raise ValueError("max_results must be positive") 

488 

489 i = 0 

490 for page in page_iter: 

491 if max_results is not None and i >= max_results: 

492 break 

493 yield page 

494 i += 1 

495 

496 

497def _item_to_entry(iterator, resource, loggers): 

498 """Convert a log entry resource to the native object. 

499 

500 .. note:: 

501 

502 This method does not have the correct signature to be used as 

503 the ``item_to_value`` argument to 

504 :class:`~google.api_core.page_iterator.Iterator`. It is intended to be 

505 patched with a mutable ``loggers`` argument that can be updated 

506 on subsequent calls. For an example, see how the method is 

507 used above in :meth:`_LoggingAPI.list_entries`. 

508 

509 Args: 

510 iterator (google.api_core.page_iterator.Iterator): The iterator that 

511 is currently in use. 

512 resource (dict): Log entry JSON resource returned from the API. 

513 loggers (Mapping[str, logging_v2.logger.Logger]): 

514 A mapping of logger fullnames -> loggers. If the logger 

515 that owns the entry is not in ``loggers``, the entry 

516 will have a newly-created logger. 

517 

518 Returns: 

519 ~logging_v2.entries._BaseEntry: The next log entry in the page. 

520 """ 

521 return entry_from_resource(resource, iterator.client, loggers) 

522 

523 

524def _item_to_sink(iterator, resource): 

525 """Convert a sink resource to the native object. 

526 

527 Args: 

528 iterator (google.api_core.page_iterator.Iterator): The iterator that 

529 is currently in use. 

530 resource (dict): Sink JSON resource returned from the API. 

531 

532 Returns: 

533 ~logging_v2.sink.Sink: The next sink in the page. 

534 """ 

535 return Sink.from_api_repr(resource, iterator.client) 

536 

537 

538def _item_to_metric(iterator, resource): 

539 """Convert a metric resource to the native object. 

540 

541 Args: 

542 iterator (google.api_core.page_iterator.Iterator): The iterator that 

543 is currently in use. 

544 resource (dict): Sink JSON resource returned from the API. 

545 

546 Returns: 

547 ~logging_v2.metric.Metric: 

548 The next metric in the page. 

549 """ 

550 return Metric.from_api_repr(resource, iterator.client)