Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys

from google.api import monitored_resource_pb2
from google.cloud.logging_v2.services.logging_service_v2 import LoggingServiceV2Client
from google.cloud.logging_v2.types import LogEntry
from google.cloud.logging_v2.types import WriteLogEntriesRequest
Comment on lines +18 to +20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It is recommended to import classes from the public google.cloud.logging_v2 namespace rather than from deep internal submodules like services or types. This follows best practices for using Google Cloud client libraries and makes the code more resilient to internal package changes.

Suggested change
from google.cloud.logging_v2.services.logging_service_v2 import LoggingServiceV2Client
from google.cloud.logging_v2.types import LogEntry
from google.cloud.logging_v2.types import WriteLogEntriesRequest
from google.cloud.logging_v2 import LoggingServiceV2Client
from google.cloud.logging_v2 import LogEntry
from google.cloud.logging_v2 import WriteLogEntriesRequest

from google.logging.type import log_severity_pb2


# [START logging_write_log_entry]
def write_log_entry(project_id: str) -> None:
"""Writes text and structured log entries to Cloud Logging."""

client = LoggingServiceV2Client()
log_name = f"projects/{project_id}/logs/python-example-log"
resource = monitored_resource_pb2.MonitoredResource(type="global")
labels = {"sample": "write-log-entry"}

text_entry = LogEntry(
log_name=log_name,
resource=resource,
severity=log_severity_pb2.INFO,
labels=labels,
text_payload="Text log entry written from Python.",
)

struct_entry = LogEntry(
log_name=log_name,
resource=resource,
severity=log_severity_pb2.WARNING,
labels=labels,
json_payload={
"message": "Structured log entry written from Python.",
"component": "sample",
},
)

client.write_log_entries(
request=WriteLogEntriesRequest(
entries=[text_entry],
)
)
print("Wrote one text log entry.")

client.write_log_entries(
request=WriteLogEntriesRequest(
entries=[text_entry, struct_entry],
)
)
print("Wrote a batch of text and structured log entries.")


# [END logging_write_log_entry]


if __name__ == "__main__":
write_log_entry(project_id=sys.argv[1])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing sys.argv[1] without checking the number of arguments will cause an IndexError if the script is executed without a project ID. Adding a simple check with a usage message improves the robustness and usability of the sample.

Suggested change
write_log_entry(project_id=sys.argv[1])
if len(sys.argv) < 2:
print(f"Usage: python {sys.argv[0]} <project_id>")
sys.exit(1)
write_log_entry(project_id=sys.argv[1])

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest import mock

from google.logging.type import log_severity_pb2

import write_log_entry


def test_write_log_entry(capsys):
project_id = "my-project"

with mock.patch.object(write_log_entry, "LoggingServiceV2Client") as client:
write_log_entry.write_log_entry(project_id)

logging_client = client.return_value
assert logging_client.write_log_entries.call_count == 2

single_request = logging_client.write_log_entries.call_args_list[0].kwargs["request"]
assert len(single_request.entries) == 1

text_entry = single_request.entries[0]
assert text_entry.log_name == f"projects/{project_id}/logs/python-example-log"
assert text_entry.resource.type == "global"
assert text_entry.severity == log_severity_pb2.INFO
assert text_entry.labels["sample"] == "write-log-entry"
assert text_entry.text_payload == "Text log entry written from Python."

batch_request = logging_client.write_log_entries.call_args_list[1].kwargs["request"]
assert len(batch_request.entries) == 2
assert batch_request.entries[0].text_payload == text_entry.text_payload

struct_entry = batch_request.entries[1]
assert struct_entry.resource.type == "global"
assert struct_entry.severity == log_severity_pb2.WARNING
assert struct_entry.labels["sample"] == "write-log-entry"
assert (
struct_entry.json_payload["message"]
== "Structured log entry written from Python."
)
assert struct_entry.json_payload["component"] == "sample"

out, _ = capsys.readouterr()
assert "Wrote one text log entry." in out
assert "Wrote a batch of text and structured log entries." in out
Loading