Skip to content

Commit 57d8fc7

Browse files
GWealecopybara-github
authored andcommitted
perf(models): guard debug log evaluation with isEnabledFor
Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 917411239
1 parent e7ca943 commit 57d8fc7

4 files changed

Lines changed: 132 additions & 3 deletions

File tree

src/google/adk/models/google_llm.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ async def generate_content_async(
252252
aggregator = StreamingResponseAggregator()
253253
async with Aclosing(responses) as agen:
254254
async for response in agen:
255-
logger.debug(_build_response_log(response))
255+
if logger.isEnabledFor(logging.DEBUG):
256+
logger.debug(_build_response_log(response))
256257
async with Aclosing(
257258
aggregator.process_response(response)
258259
) as aggregator_gen:
@@ -274,7 +275,8 @@ async def generate_content_async(
274275
config=llm_request.config,
275276
)
276277
logger.info('Response received from the model.')
277-
logger.debug(_build_response_log(response))
278+
if logger.isEnabledFor(logging.DEBUG):
279+
logger.debug(_build_response_log(response))
278280

279281
llm_response = LlmResponse.create(response)
280282
if cache_metadata:

src/google/adk/models/lite_llm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2224,7 +2224,8 @@ async def generate_content_async(
22242224

22252225
self._maybe_append_user_content(llm_request)
22262226
_append_fallback_user_content_if_missing(llm_request)
2227-
logger.debug(_build_request_log(llm_request))
2227+
if logger.isEnabledFor(logging.DEBUG):
2228+
logger.debug(_build_request_log(llm_request))
22282229

22292230
effective_model = llm_request.model or self.model
22302231
messages, tools, response_format, generation_params = (

tests/unittests/models/test_google_llm.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import logging
1516
import os
1617
import sys
1718
from typing import Optional
@@ -2263,3 +2264,96 @@ async def __aexit__(self, *args):
22632264
# Verify the final speech_config is still None
22642265
assert config_arg.speech_config is None
22652266
assert isinstance(connection, GeminiLlmConnection)
2267+
2268+
2269+
@pytest.mark.asyncio
2270+
@pytest.mark.parametrize(
2271+
"log_level,should_call",
2272+
[
2273+
(logging.WARNING, False),
2274+
(logging.INFO, False),
2275+
(logging.DEBUG, True),
2276+
],
2277+
)
2278+
async def test_generate_content_async_skips_response_log_build_above_debug(
2279+
gemini_llm,
2280+
llm_request,
2281+
generate_content_response,
2282+
log_level,
2283+
should_call,
2284+
):
2285+
gemini_logger = logging.getLogger("google_adk.google.adk.models.google_llm")
2286+
original_level = gemini_logger.level
2287+
gemini_logger.setLevel(log_level)
2288+
try:
2289+
with mock.patch(
2290+
"google.adk.models.google_llm._build_response_log",
2291+
return_value="log",
2292+
) as mock_build:
2293+
with mock.patch.object(gemini_llm, "api_client") as mock_client:
2294+
2295+
async def mock_coro():
2296+
return generate_content_response
2297+
2298+
mock_client.aio.models.generate_content.return_value = mock_coro()
2299+
2300+
async for _ in gemini_llm.generate_content_async(
2301+
llm_request, stream=False
2302+
):
2303+
pass
2304+
2305+
assert mock_build.called is should_call
2306+
finally:
2307+
gemini_logger.setLevel(original_level)
2308+
2309+
2310+
@pytest.mark.asyncio
2311+
@pytest.mark.parametrize(
2312+
"log_level,should_call",
2313+
[
2314+
(logging.WARNING, False),
2315+
(logging.INFO, False),
2316+
(logging.DEBUG, True),
2317+
],
2318+
)
2319+
async def test_generate_content_async_stream_skips_response_log_build_above_debug(
2320+
gemini_llm, llm_request, log_level, should_call
2321+
):
2322+
mock_responses = [
2323+
types.GenerateContentResponse(
2324+
candidates=[
2325+
types.Candidate(
2326+
content=Content(
2327+
role="model", parts=[Part.from_text(text="hi")]
2328+
),
2329+
finish_reason=types.FinishReason.STOP,
2330+
)
2331+
]
2332+
),
2333+
]
2334+
2335+
gemini_logger = logging.getLogger("google_adk.google.adk.models.google_llm")
2336+
original_level = gemini_logger.level
2337+
gemini_logger.setLevel(log_level)
2338+
try:
2339+
with mock.patch(
2340+
"google.adk.models.google_llm._build_response_log",
2341+
return_value="log",
2342+
) as mock_build:
2343+
with mock.patch.object(gemini_llm, "api_client") as mock_client:
2344+
2345+
async def mock_coro():
2346+
return MockAsyncIterator(mock_responses)
2347+
2348+
mock_client.aio.models.generate_content_stream.return_value = (
2349+
mock_coro()
2350+
)
2351+
2352+
async for _ in gemini_llm.generate_content_async(
2353+
llm_request, stream=True
2354+
):
2355+
pass
2356+
2357+
assert mock_build.called is should_call
2358+
finally:
2359+
gemini_logger.setLevel(original_level)

tests/unittests/models/test_litellm.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from unittest.mock import AsyncMock
2525
from unittest.mock import MagicMock
2626
from unittest.mock import Mock
27+
from unittest.mock import patch
2728
import warnings
2829

2930
from google.adk.models.lite_llm import _append_fallback_user_content_if_missing
@@ -4954,3 +4955,34 @@ async def test_content_to_message_param_anthropic_no_signature_falls_back():
49544955
# Falls back to reasoning_content when no signatures present
49554956
assert result.get("reasoning_content") == "thinking without sig"
49564957
assert "thinking_blocks" not in result
4958+
4959+
4960+
@pytest.mark.asyncio
4961+
@pytest.mark.parametrize(
4962+
"log_level,should_call",
4963+
[
4964+
(logging.WARNING, False),
4965+
(logging.INFO, False),
4966+
(logging.DEBUG, True),
4967+
],
4968+
)
4969+
async def test_generate_content_async_skips_request_log_build_above_debug(
4970+
mock_acompletion, lite_llm_instance, log_level, should_call
4971+
):
4972+
del mock_acompletion # unused; lite_llm_instance is wired to it
4973+
litellm_logger = logging.getLogger("google_adk.google.adk.models.lite_llm")
4974+
original_level = litellm_logger.level
4975+
litellm_logger.setLevel(log_level)
4976+
try:
4977+
with patch(
4978+
"google.adk.models.lite_llm._build_request_log",
4979+
return_value="log",
4980+
) as mock_build:
4981+
async for _ in lite_llm_instance.generate_content_async(
4982+
LLM_REQUEST_WITH_FUNCTION_DECLARATION
4983+
):
4984+
pass
4985+
4986+
assert mock_build.called is should_call
4987+
finally:
4988+
litellm_logger.setLevel(original_level)

0 commit comments

Comments
 (0)