Skip to content

Commit c5217f9

Browse files
Jon Wayne Parrottbusunkim96
Jon Wayne Parrott
authored andcommitted
Update logging samples to fit new style guide and match Node.js samples. [(#435)](GoogleCloudPlatform/python-docs-samples#435)
1 parent cbbe6df commit c5217f9

File tree

6 files changed

+403
-0
lines changed

6 files changed

+403
-0
lines changed

samples/snippets/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Stackdriver Logging v2 API Samples
2+
3+
`snippets.py` is a simple command-line program to demonstrate writing to a log,
4+
listing its entries, and deleting it.
5+
6+
`export.py` demonstrates how to interact with sinks which are used to export
7+
logs to Google Cloud Storage, Cloud Pub/Sub, or BigQuery. The sample uses
8+
Google Cloud Storage, but can be easily adapted for other outputs.
9+
10+
<!-- auto-doc-link -->
11+
<!-- end-auto-doc-link -->
12+
13+
## Prerequisites
14+
15+
All samples require a [Google Cloud Project](https://console.cloud.google.com).
16+
17+
To run `export.py`, you will also need a Google Cloud Storage Bucket.
18+
19+
gsutil mb gs://[YOUR_PROJECT_ID]
20+
21+
You must add Cloud Logging as an owner to the bucket. To do so, add
22+
`[email protected]` as an owner to the bucket. See the
23+
[exportings logs](https://cloud.google.com/logging/docs/export/configure_export#configuring_log_sinks)
24+
docs for complete details.
25+
26+
# Running locally
27+
28+
Use the [Cloud SDK](https://cloud.google.com/sdk) to provide authentication:
29+
30+
gcloud beta auth application-default login
31+
32+
Run the samples:
33+
34+
python snippets.py -h
35+
python export.py -h
36+

samples/snippets/export.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc. All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import argparse
18+
19+
from gcloud import logging
20+
21+
22+
def list_sinks():
23+
"""Lists all sinks."""
24+
logging_client = logging.Client()
25+
26+
sinks = []
27+
token = None
28+
while True:
29+
new_sinks, token = logging_client.list_sinks(page_token=token)
30+
sinks.extend(new_sinks)
31+
if token is None:
32+
break
33+
34+
if not sinks:
35+
print('No sinks.')
36+
37+
for sink in sinks:
38+
print('{}: {} -> {}'.format(sink.name, sink.filter_, sink.destination))
39+
40+
41+
def create_sink(sink_name, destination_bucket, filter_):
42+
"""Creates a sink to export logs to the given Cloud Storage bucket.
43+
44+
The filter determines which logs this sink matches and will be exported
45+
to the destination. For example a filter of 'severity>=INFO' will send
46+
all logs that have a severity of INFO or greater to the destination.
47+
See https://cloud.google.com/logging/docs/view/advanced_filters for more
48+
filter information.
49+
"""
50+
logging_client = logging.Client()
51+
52+
# The destination can be a Cloud Storage bucket, a Cloud Pub/Sub topic,
53+
# or a BigQuery dataset. In this case, it is a Cloud Storage Bucket.
54+
# See https://cloud.google.com/logging/docs/api/tasks/exporting-logs for
55+
# information on the destination format.
56+
destination = 'storage.googleapis.com/{bucket}'.format(
57+
bucket=destination_bucket)
58+
59+
sink = logging_client.sink(
60+
sink_name,
61+
filter_,
62+
destination)
63+
64+
if sink.exists():
65+
print('Sink {} already exists.'.format(sink.name))
66+
return
67+
68+
sink.create()
69+
print('Created sink {}'.format(sink.name))
70+
71+
72+
def update_sink(sink_name, filter_):
73+
"""Changes a sink's filter.
74+
75+
The filter determines which logs this sink matches and will be exported
76+
to the destination. For example a filter of 'severity>=INFO' will send
77+
all logs that have a severity of INFO or greater to the destination.
78+
See https://cloud.google.com/logging/docs/view/advanced_filters for more
79+
filter information.
80+
"""
81+
logging_client = logging.Client()
82+
sink = logging_client.sink(sink_name)
83+
84+
sink.reload()
85+
86+
sink.filter_ = filter_
87+
print('Updated sink {}'.format(sink.name))
88+
sink.update()
89+
# [END update]
90+
91+
92+
def delete_sink(sink_name):
93+
"""Deletes a sink."""
94+
logging_client = logging.Client()
95+
sink = logging_client.sink(sink_name)
96+
97+
sink.delete()
98+
99+
print('Deleted sink {}'.format(sink.name))
100+
101+
102+
if __name__ == '__main__':
103+
parser = argparse.ArgumentParser(
104+
description=__doc__,
105+
formatter_class=argparse.RawDescriptionHelpFormatter
106+
)
107+
108+
subparsers = parser.add_subparsers(dest='command')
109+
subparsers.add_parser('list', help=list_sinks.__doc__)
110+
111+
create_parser = subparsers.add_parser('create', help=list_sinks.__doc__)
112+
create_parser.add_argument(
113+
'sink_name',
114+
help='Name of the log export sink.')
115+
create_parser.add_argument(
116+
'destination_bucket',
117+
help='Cloud Storage bucket where logs will be exported.')
118+
create_parser.add_argument(
119+
'filter',
120+
help='The filter used to match logs.')
121+
122+
update_parser = subparsers.add_parser('update', help=update_sink.__doc__)
123+
update_parser.add_argument(
124+
'sink_name',
125+
help='Name of the log export sink.')
126+
update_parser.add_argument(
127+
'filter',
128+
help='The filter used to match logs.')
129+
130+
delete_parser = subparsers.add_parser('delete', help=delete_sink.__doc__)
131+
delete_parser.add_argument(
132+
'sink_name',
133+
help='Name of the log export sink.')
134+
135+
args = parser.parse_args()
136+
137+
if args.command == 'list':
138+
list_sinks()
139+
elif args.command == 'create':
140+
create_sink(args.sink_name, args.destination_bucket, args.filter)
141+
elif args.command == 'update':
142+
update_sink(args.sink_name, args.filter)
143+
elif args.command == 'delete':
144+
delete_sink(args.sink_name)

samples/snippets/export_test.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright 2016 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import export
16+
from gcloud import logging
17+
from gcp.testing import eventually_consistent
18+
import pytest
19+
20+
TEST_SINK_NAME = 'example_sink'
21+
TEST_SINK_FILTER = 'severity>=CRITICAL'
22+
23+
24+
@pytest.fixture
25+
def example_sink(cloud_config):
26+
client = logging.Client()
27+
28+
sink = client.sink(
29+
TEST_SINK_NAME,
30+
TEST_SINK_FILTER,
31+
'storage.googleapis.com/{bucket}'.format(
32+
bucket=cloud_config.storage_bucket))
33+
34+
if sink.exists():
35+
sink.delete()
36+
37+
sink.create()
38+
39+
return sink
40+
41+
42+
def test_list(example_sink, capsys):
43+
@eventually_consistent.call
44+
def _():
45+
export.list_sinks()
46+
out, _ = capsys.readouterr()
47+
assert example_sink.name in out
48+
49+
50+
def test_create(cloud_config, capsys):
51+
export.create_sink(
52+
TEST_SINK_NAME,
53+
TEST_SINK_FILTER,
54+
'storage.googleapis.com/{bucket}'.format(
55+
bucket=cloud_config.storage_bucket))
56+
57+
out, _ = capsys.readouterr()
58+
assert TEST_SINK_NAME in out
59+
60+
61+
def test_update(example_sink, capsys):
62+
updated_filter = 'severity>=INFO'
63+
export.update_sink(TEST_SINK_NAME, updated_filter)
64+
65+
example_sink.reload()
66+
assert example_sink.filter_ == updated_filter
67+
68+
69+
def test_delete(example_sink, capsys):
70+
export.delete_sink(TEST_SINK_NAME)
71+
assert not example_sink.exists()

samples/snippets/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
gcloud==0.17.0

samples/snippets/snippets.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc. All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""This application demonstrates how to perform basic operations on logs and
18+
log entries with Stackdriver Logging.
19+
20+
For more information, see the README.md under /logging and the
21+
documentation at https://cloud.google.com/logging/docs.
22+
"""
23+
24+
import argparse
25+
26+
from gcloud import logging
27+
28+
29+
def write_entry(logger_name):
30+
"""Writes log entries to the given logger."""
31+
logging_client = logging.Client()
32+
33+
# This log can be found in the Cloud Logging console under 'Custom Logs'.
34+
logger = logging_client.logger(logger_name)
35+
36+
# Make a simple text log
37+
logger.log_text('Hello, world!')
38+
39+
# Simple text log with severity.
40+
logger.log_text('Goodbye, world!', severity='ERROR')
41+
42+
# Struct log. The struct can be any JSON-serializable dictionary.
43+
logger.log_struct({
44+
'name': 'King Arthur',
45+
'quest': 'Find the Holy Grail',
46+
'favorite_color': 'Blue'
47+
})
48+
49+
print('Wrote logs to {}.'.format(logger.name))
50+
51+
52+
def list_entries(logger_name):
53+
"""Lists the most recent entries for a given logger."""
54+
logging_client = logging.Client()
55+
logger = logging_client.logger(logger_name)
56+
57+
print('Listing entries for logger {}:'.format(logger.name))
58+
59+
entries = []
60+
page_token = None
61+
62+
while True:
63+
new_entries, page_token = logger.list_entries(page_token=page_token)
64+
entries.extend(new_entries)
65+
if not page_token:
66+
break
67+
68+
for entry in entries:
69+
timestamp = entry.timestamp.isoformat()
70+
print('* {}: {}'.format
71+
(timestamp, entry.payload))
72+
73+
74+
def delete_logger(logger_name):
75+
"""Deletes a logger and all its entries.
76+
77+
Note that a deletion can take several minutes to take effect.
78+
"""
79+
logging_client = logging.Client()
80+
logger = logging_client.logger(logger_name)
81+
82+
logger.delete()
83+
84+
print('Deleted all logging entries for {}'.format(logger.name))
85+
86+
87+
if __name__ == '__main__':
88+
parser = argparse.ArgumentParser(
89+
description=__doc__,
90+
formatter_class=argparse.RawDescriptionHelpFormatter
91+
)
92+
parser.add_argument(
93+
'logger_name', help='Logger name', default='example_log')
94+
subparsers = parser.add_subparsers(dest='command')
95+
subparsers.add_parser('list', help=list_entries.__doc__)
96+
subparsers.add_parser('write', help=write_entry.__doc__)
97+
subparsers.add_parser('delete', help=delete_logger.__doc__)
98+
99+
args = parser.parse_args()
100+
101+
if args.command == 'list':
102+
list_entries(args.logger_name)
103+
elif args.command == 'write':
104+
write_entry(args.logger_name)
105+
elif args.command == 'delete':
106+
delete_logger(args.logger_name)

0 commit comments

Comments
 (0)