Configure logging to log to Stackdriver #155
Conversation
…google-api-client-python
@@ -29,11 +29,8 @@ | |||
from google.cloud.security.common.data_access.errors import NoResultsError | |||
from google.cloud.security.common.data_access.sql_queries import create_tables | |||
from google.cloud.security.common.data_access.sql_queries import select_data | |||
from google.cloud.security.common.util.log_util import LogUtil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to add back in logging support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it wasn't used anywhere in this file.
@@ -18,11 +18,8 @@ | |||
import tempfile | |||
|
|||
from google.cloud.security.common.data_access.errors import CSVFileError | |||
from google.cloud.security.common.util.log_util import LogUtil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to add back in logging support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure the imports are consistent, since you started cleaning them up in the PR.
We should be importing the module, not the class:
https://google.github.io/styleguide/pyguide.html#Imports
from google.cloud.security.common.gcp_api._base_client import _BaseClient | ||
|
||
def is_compute_engine_instance(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a bit out of place to put this here. I think a module under ../util would be better.
@@ -0,0 +1,171 @@ | |||
# Copyright 2016 Google Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How will this stay in sync with the file in google-cloud-python?
FLAGS = flags.FLAGS | ||
flags.DEFINE_boolean('use_cloud_logging', False, | ||
'Use Cloud Logging, if available.') | ||
flags.DEFINE_boolean('nouse_cloud_logging', False, 'Do not use Cloud Logging.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DEFINE_boolean automatically creates the no version of the flag, you don't have to do that yourself. The no version will set the flag value False.
And based on the code below, the default value should be None, not False.
|
||
# Determine whether to use cloud logger based on environment. | ||
if should_use_cloud_logger is None: | ||
should_use_cloud_logger = is_gce |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be simplified to not require the should_use_cloud_logger var and just the following.
if FLAGS.use_cloud_logging or (FLAGS.use_cloud_logging is None and is_gce):
...
An instance of the configured logger. | ||
""" | ||
formatter = logging.Formatter(LOG_FORMAT) | ||
console_handler = logging.StreamHandler() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we default to SysLogHandler instead? Or maybe use logging.config.fileConfig and include a default logging configuration that can be overridden by changing the configuration file rather than changing the code?
import logging | ||
|
||
from google.cloud.security.common.gcp_api._base_client import _BaseClient | ||
# pylint: disable=line-too-long |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to re-enable this check after the imports to catch the other places in this file where line is too long.
# pylint: disable=line-too-long | ||
"""Cloud Logging Handler. | ||
|
||
See: https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/logging/google/cloud/logging/handlers/handlers.py |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an issue with just directly using google-cloud-python instead of importing pieces of it? How do we get patches / updates if there are bug fixes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on not importing pieces of code like this if we can avoid it. But the issue is different versions of oauth2client being used. Have other people done something similar to here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks for working through this one.
|
||
Most of this code has been lifted from: | ||
|
||
https://github.com/GoogleCloudPlatform/google-cloud-python/blob/master/logging/google/cloud/logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does licensing allow this? Should we just add to third_party?
"""Convert a timestamp to a string. | ||
|
||
Args: | ||
:type value: :class:`datetime.datetime` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: make pydoc match to the rest of the code-base. Fix throughout please.
from google.cloud.security.common.gcp_api._base_client import _BaseClient | ||
|
||
def is_compute_engine_instance(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do callers need the error msg or can we simplify this by just returning a boolean?
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Module containing base class for logging transport.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we just pip install google-cloud-logging and use it as a dependency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
googleapiclient and google-cloud-python don't play together at all. installing both breaks the entire environment.
console_handler.setFormatter(formatter) | ||
logger_instance = logging.getLogger(module_name) | ||
logger_instance.addHandler(console_handler) | ||
logger_instance.setLevel(logging.INFO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to look into making this an argument at execution.
Args: | ||
module_name: The name of the module for which to configure logging. | ||
""" | ||
(is_gce, _) = compute.is_compute_engine_instance() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment above about not needing the error message. I suggest just returning the boolean result.
logger_instance = logging.getLogger(module_name) | ||
logger_instance.addHandler(cloud_handler) | ||
|
||
if FLAGS.debug: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this done in get_logger? It could be confusing to debug the code to understand where this is getting set if we set verbosity in two different spots.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can't use flags until they are parsed, which happens in app.run(). So the strategy is to attach the default log handler at the toplevel (e.g. module import) and then attach the stackdriver handler after app.run().
I haven't cleaned up all the imports yet, mostly the ones that were nearby the log_util import. Changed logger to use the SysLogHandler and removed the cloud logging related stuff. PTAL. |
@@ -87,11 +88,11 @@ def test_get_loaded_count(self): | |||
def test_error_is_handled_in_get_loaded_count(self): | |||
"""Test error from get_loaded_count is handled.""" | |||
|
|||
self.pipeline.logger = mock.create_autospec( | |||
LogUtil).setup_logging('foo') | |||
base_pipeline.LOGGER = mock.create_autospec( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@blueandgold FYI I tweaked your pipeline unit tests to reference the [MODULE_NAME].LOGGER property and made the pipeline.logger property a global "LOGGER" variable to be consistent across the codebase. Let me know if this looks ok; I'm not totally sure what's the best way here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem if that works. 👍
Adding |
Logger has a console handler (logging.StreamHandler) and a syslog handler (logging.handlers.SysLogHandler). On GCE instance we install the fluentd logging agent which will transparently pass the syslog entries to stackdriver
resolves #73