Repository: googleapis/python-logging

Issue:
Support log name in StructuredLoggingHandler
 **Is your feature request related to a problem? Please describe.**

When configuring locally, i can set the logName by using `client.setup_logging(name='my-api')` and it works correctly. My logs show up as 'my-api' in the "select log name" dropdown in the log explorer. However, the moment I deploy it to GKE, it crashes stating the `name` argument is unexpected. Digging through the code, I noticed it is because, when deployed locally, it selects CloudLoggingHandler which accepts the `name` argument, but when it's deployed to GKE, it selects StructuredLoggingHandler which does *not*.  This is frustrating for a couple reasons:

1. It makes the code less portable because in order to avoid the error, the startup procedure needs to know where it's being deployed so it knows whether or not it should add the argument.
2. If i don't set it, all of the logs show up in a log named 'python' which is confusing when you have multiple python components hosted in the same GCP project all logging to 'python'.
3. I suppose I could just add a label to all logs with the application's name using `logging.getLogger('my-api')` but then that forces me to add extras to every log statement if I want to add labels to help further scope my logs.

 **Describe the solution you'd like**
Support the log name in StructuredLoggingHandler. For comparison, our .NET solutions don't have this problem. It behaves the same way regardless of where it's deployed.


 **Describe alternatives you've considered**
Point 3 of the problem statement. This is additionally problematic in a large enterprise where we're trying to build tools around log routing due to the inconsistency of how logs are partitioned. It's an inconsistent experience if nothing else.

 **Additional context**



Discussion:

Patch:
diff --git a/google/cloud/logging_v2/handlers/handlers.py b/google/cloud/logging_v2/handlers/handlers.py
index 34bb018..3d6ab9d 100644
--- a/google/cloud/logging_v2/handlers/handlers.py
+++ b/google/cloud/logging_v2/handlers/handlers.py
@@ -157,6 +157,7 @@ class CloudLoggingHandler(logging.StreamHandler):
         resource=None,
         labels=None,
         stream=None,
+        **kwargs,
     ):
         """
         Args:
diff --git a/google/cloud/logging_v2/handlers/structured_log.py b/google/cloud/logging_v2/handlers/structured_log.py
index e609409..dcba02c 100644
--- a/google/cloud/logging_v2/handlers/structured_log.py
+++ b/google/cloud/logging_v2/handlers/structured_log.py
@@ -63,7 +63,13 @@ class StructuredLogHandler(logging.StreamHandler):
     """
 
     def __init__(
-        self, *, labels=None, stream=None, project_id=None, json_encoder_cls=None
+        self,
+        *,
+        labels=None,
+        stream=None,
+        project_id=None,
+        json_encoder_cls=None,
+        **kwargs
     ):
         """
         Args:


Test patch:
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index 2f6736d..2d12a28 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -894,6 +894,42 @@ class TestClient(unittest.TestCase):
         }
         self.assertEqual(kwargs, expected_kwargs)
 
+    def test_setup_logging_w_extra_kwargs_structured_log(self):
+        import io
+        from google.cloud.logging.handlers import StructuredLogHandler
+        from google.cloud.logging import Resource
+        from google.cloud.logging_v2.client import _GKE_RESOURCE_TYPE
+
+        name = "test-logger"
+        resource = Resource(_GKE_RESOURCE_TYPE, {"resource_label": "value"})
+        labels = {"handler_label": "value"}
+        stream = io.BytesIO()
+
+        credentials = _make_credentials()
+        client = self._make_one(
+            project=self.PROJECT, credentials=credentials, _use_grpc=False
+        )
+
+        with mock.patch("google.cloud.logging_v2.client.setup_logging") as mocked:
+            client.setup_logging(
+                name=name, resource=resource, labels=labels, stream=stream
+            )
+
+        self.assertEqual(len(mocked.mock_calls), 1)
+        _, args, kwargs = mocked.mock_calls[0]
+
+        (handler,) = args
+        self.assertIsInstance(handler, StructuredLogHandler)
+
+        expected_kwargs = {
+            "excluded_loggers": (
+                "google.api_core.bidi",
+                "werkzeug",
+            ),
+            "log_level": 20,
+        }
+        self.assertEqual(kwargs, expected_kwargs)
+
 
 class _Connection(object):
     _called_with = None