Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b74d2a8

Browse filesBrowse files
fix: client_info default values (#681)
1 parent b1d7d29 commit b74d2a8
Copy full SHA for b74d2a8

File tree

Expand file treeCollapse file tree

6 files changed

+147
-3
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+147
-3
lines changed

‎google/cloud/logging_v2/_gapic.py

Copy file name to clipboardExpand all lines: google/cloud/logging_v2/_gapic.py
+37-3Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
from google.cloud.logging_v2.sink import Sink
3636
from google.cloud.logging_v2.metric import Metric
3737

38+
from google.api_core import client_info
39+
from google.api_core import gapic_v1
40+
3841

3942
class _LoggingAPI(object):
4043
"""Helper mapping logging-related APIs."""
@@ -562,6 +565,22 @@ def _log_entry_mapping_to_pb(mapping):
562565
return LogEntryPB(entry_pb)
563566

564567

568+
def _client_info_to_gapic(input_info):
569+
"""
570+
Helper function to convert api_core.client_info to
571+
api_core.gapic_v1.client_info subclass
572+
"""
573+
return gapic_v1.client_info.ClientInfo(
574+
python_version=input_info.python_version,
575+
grpc_version=input_info.grpc_version,
576+
api_core_version=input_info.api_core_version,
577+
gapic_version=input_info.gapic_version,
578+
client_library_version=input_info.client_library_version,
579+
user_agent=input_info.user_agent,
580+
rest_version=input_info.rest_version,
581+
)
582+
583+
565584
def make_logging_api(client):
566585
"""Create an instance of the Logging API adapter.
567586
@@ -572,9 +591,14 @@ def make_logging_api(client):
572591
Returns:
573592
_LoggingAPI: A metrics API instance with the proper credentials.
574593
"""
594+
info = client._client_info
595+
if type(info) == client_info.ClientInfo:
596+
# convert into gapic-compatible subclass
597+
info = _client_info_to_gapic(info)
598+
575599
generated = LoggingServiceV2Client(
576600
credentials=client._credentials,
577-
client_info=client._client_info,
601+
client_info=info,
578602
client_options=client._client_options,
579603
)
580604
return _LoggingAPI(generated, client)
@@ -590,9 +614,14 @@ def make_metrics_api(client):
590614
Returns:
591615
_MetricsAPI: A metrics API instance with the proper credentials.
592616
"""
617+
info = client._client_info
618+
if type(info) == client_info.ClientInfo:
619+
# convert into gapic-compatible subclass
620+
info = _client_info_to_gapic(info)
621+
593622
generated = MetricsServiceV2Client(
594623
credentials=client._credentials,
595-
client_info=client._client_info,
624+
client_info=info,
596625
client_options=client._client_options,
597626
)
598627
return _MetricsAPI(generated, client)
@@ -608,9 +637,14 @@ def make_sinks_api(client):
608637
Returns:
609638
_SinksAPI: A metrics API instance with the proper credentials.
610639
"""
640+
info = client._client_info
641+
if type(info) == client_info.ClientInfo:
642+
# convert into gapic-compatible subclass
643+
info = _client_info_to_gapic(info)
644+
611645
generated = ConfigServiceV2Client(
612646
credentials=client._credentials,
613-
client_info=client._client_info,
647+
client_info=info,
614648
client_options=client._client_options,
615649
)
616650
return _SinksAPI(generated, client)

‎google/cloud/logging_v2/client.py

Copy file name to clipboardExpand all lines: google/cloud/logging_v2/client.py
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ def __init__(
137137
kw_args["api_endpoint"] = api_endpoint
138138

139139
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
140144

141145
self._client_info = client_info
142146
self._client_options = client_options

‎tests/unit/gapic/logging_v2/test_config_service_v2.py

Copy file name to clipboardExpand all lines: tests/unit/gapic/logging_v2/test_config_service_v2.py
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ def test__get_default_mtls_endpoint():
9999
)
100100

101101

102+
def test_config_default_client_info_headers():
103+
import re
104+
import pkg_resources
105+
106+
# test that DEFAULT_CLIENT_INFO contains the expected gapic headers
107+
gapic_header_regex = re.compile(
108+
r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+"
109+
)
110+
detected_info = (
111+
google.cloud.logging_v2.services.config_service_v2.transports.base.DEFAULT_CLIENT_INFO
112+
)
113+
assert detected_info is not None
114+
detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" ")))
115+
assert gapic_header_regex.match(detected_agent)
116+
117+
102118
@pytest.mark.parametrize(
103119
"client_class,transport_name",
104120
[

‎tests/unit/gapic/logging_v2/test_logging_service_v2.py

Copy file name to clipboardExpand all lines: tests/unit/gapic/logging_v2/test_logging_service_v2.py
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ def modify_default_endpoint(client):
7171
)
7272

7373

74+
def test_logging_default_client_info_headers():
75+
import re
76+
import pkg_resources
77+
78+
# test that DEFAULT_CLIENT_INFO contains the expected gapic headers
79+
gapic_header_regex = re.compile(
80+
r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+"
81+
)
82+
detected_info = (
83+
google.cloud.logging_v2.services.logging_service_v2.transports.base.DEFAULT_CLIENT_INFO
84+
)
85+
assert detected_info is not None
86+
detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" ")))
87+
assert gapic_header_regex.match(detected_agent)
88+
89+
7490
def test__get_default_mtls_endpoint():
7591
api_endpoint = "example.googleapis.com"
7692
api_mtls_endpoint = "example.mtls.googleapis.com"

‎tests/unit/gapic/logging_v2/test_metrics_service_v2.py

Copy file name to clipboardExpand all lines: tests/unit/gapic/logging_v2/test_metrics_service_v2.py
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ def test__get_default_mtls_endpoint():
9999
)
100100

101101

102+
def test_metrics_default_client_info_headers():
103+
import re
104+
import pkg_resources
105+
106+
# test that DEFAULT_CLIENT_INFO contains the expected gapic headers
107+
gapic_header_regex = re.compile(
108+
r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+"
109+
)
110+
detected_info = (
111+
google.cloud.logging_v2.services.metrics_service_v2.transports.base.DEFAULT_CLIENT_INFO
112+
)
113+
assert detected_info is not None
114+
detected_agent = " ".join(sorted(detected_info.to_user_agent().split(" ")))
115+
assert gapic_header_regex.match(detected_agent)
116+
117+
102118
@pytest.mark.parametrize(
103119
"client_class,transport_name",
104120
[

‎tests/unit/test_client.py

Copy file name to clipboardExpand all lines: tests/unit/test_client.py
+58Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@
1616
from datetime import datetime
1717
from datetime import timedelta
1818
from datetime import timezone
19+
import re
1920

2021
import unittest
2122

2223
import mock
2324

25+
VENEER_HEADER_REGEX = re.compile(
26+
r"gapic\/[0-9]+\.[\w.-]+ gax\/[0-9]+\.[\w.-]+ gccl\/[0-9]+\.[\w.-]+ gl-python\/[0-9]+\.[\w.-]+ grpc\/[0-9]+\.[\w.-]+"
27+
)
28+
2429

2530
def _make_credentials():
2631
import google.auth.credentials
@@ -148,6 +153,59 @@ def make_api(client_obj):
148153
again = client.logging_api
149154
self.assertIs(again, api)
150155

156+
def test_veneer_grpc_headers(self):
157+
# test that client APIs have client_info populated with the expected veneer headers
158+
# required for proper instrumentation
159+
creds = _make_credentials()
160+
# ensure client info is set on client object
161+
client = self._make_one(project=self.PROJECT, credentials=creds, _use_grpc=True)
162+
self.assertIsNotNone(client._client_info)
163+
user_agent_sorted = " ".join(
164+
sorted(client._client_info.to_user_agent().split(" "))
165+
)
166+
self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted))
167+
# ensure client info is propagated to gapic wrapped methods
168+
patch = mock.patch("google.api_core.gapic_v1.method.wrap_method")
169+
with patch as gapic_mock:
170+
client.logging_api # initialize logging api
171+
client.metrics_api # initialize metrics api
172+
client.sinks_api # initialize sinks api
173+
wrapped_call_list = gapic_mock.call_args_list
174+
num_api_calls = 37 # expected number of distinct APIs in all gapic services (logging,metrics,sinks)
175+
self.assertGreaterEqual(
176+
len(wrapped_call_list),
177+
num_api_calls,
178+
"unexpected number of APIs wrapped",
179+
)
180+
for call in wrapped_call_list:
181+
client_info = call.kwargs["client_info"]
182+
self.assertIsNotNone(client_info)
183+
wrapped_user_agent_sorted = " ".join(
184+
sorted(client_info.to_user_agent().split(" "))
185+
)
186+
self.assertTrue(VENEER_HEADER_REGEX.match(wrapped_user_agent_sorted))
187+
188+
def test_veneer_http_headers(self):
189+
# test that http APIs have client_info populated with the expected veneer headers
190+
# required for proper instrumentation
191+
creds = _make_credentials()
192+
# ensure client info is set on client object
193+
client = self._make_one(
194+
project=self.PROJECT, credentials=creds, _use_grpc=False
195+
)
196+
self.assertIsNotNone(client._client_info)
197+
user_agent_sorted = " ".join(
198+
sorted(client._client_info.to_user_agent().split(" "))
199+
)
200+
self.assertTrue(VENEER_HEADER_REGEX.match(user_agent_sorted))
201+
# ensure client info is propagated to _connection object
202+
connection_user_agent = client._connection._client_info.to_user_agent()
203+
self.assertIsNotNone(connection_user_agent)
204+
connection_user_agent_sorted = " ".join(
205+
sorted(connection_user_agent.split(" "))
206+
)
207+
self.assertTrue(VENEER_HEADER_REGEX.match(connection_user_agent_sorted))
208+
151209
def test_no_gapic_ctor(self):
152210
from google.cloud.logging_v2._http import _LoggingAPI
153211

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.