From d26398fe7f9cf56aa4057e5a81f56c671a6ab8bb Mon Sep 17 00:00:00 2001
From: Marco Ziccardi <marco.ziccard@gmail.com>
Date: Fri, 26 Aug 2016 15:13:35 +0200
Subject: [PATCH] Add snippets to Logging's javadoc, LoggingSnippets class and
 tests

---
 .../logging/snippets/LoggingSnippets.java     | 545 ++++++++++++++++++
 .../logging/snippets/ITLoggingSnippets.java   | 172 ++++++
 .../com/google/cloud/logging/Logging.java     | 325 +++++++++++
 3 files changed, 1042 insertions(+)
 create mode 100644 gcloud-java-examples/src/main/java/com/google/cloud/examples/logging/snippets/LoggingSnippets.java
 create mode 100644 gcloud-java-examples/src/test/java/com/google/cloud/examples/logging/snippets/ITLoggingSnippets.java

diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/logging/snippets/LoggingSnippets.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/logging/snippets/LoggingSnippets.java
new file mode 100644
index 000000000000..7e9a17d0d750
--- /dev/null
+++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/logging/snippets/LoggingSnippets.java
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/*
+ * EDITING INSTRUCTIONS
+ * This file is referenced in Logging's javadoc. Any change to this file should be reflected in
+ * Logging's javadoc.
+ */
+
+package com.google.cloud.examples.logging.snippets;
+
+import com.google.cloud.AsyncPage;
+import com.google.cloud.MonitoredResource;
+import com.google.cloud.MonitoredResourceDescriptor;
+import com.google.cloud.Page;
+import com.google.cloud.logging.LogEntry;
+import com.google.cloud.logging.Logging;
+import com.google.cloud.logging.Logging.EntryListOption;
+import com.google.cloud.logging.Logging.ListOption;
+import com.google.cloud.logging.Logging.WriteOption;
+import com.google.cloud.logging.LoggingOptions;
+import com.google.cloud.logging.Metric;
+import com.google.cloud.logging.MetricInfo;
+import com.google.cloud.logging.Payload.JsonPayload;
+import com.google.cloud.logging.Payload.StringPayload;
+import com.google.cloud.logging.Sink;
+import com.google.cloud.logging.SinkInfo;
+import com.google.cloud.logging.SinkInfo.Destination.DatasetDestination;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class LoggingSnippets {
+
+  private final Logging logging;
+
+  public LoggingSnippets(Logging logging) {
+    this.logging = logging;
+  }
+
+  /**
+   * Example of creating a sink to export logs to a BigQuery dataset (in the
+   * {@link LoggingOptions#projectId()} project).
+   */
+  // [TARGET create(SinkInfo)]
+  // [VARIABLE "my_sink_name"]
+  // [VARIABLE "my_dataset"]
+  public Sink createSink(String sinkName, String datasetName) {
+    // [START createSink]
+    SinkInfo sinkInfo = SinkInfo.of(sinkName, DatasetDestination.of(datasetName));
+    Sink sink = logging.create(sinkInfo);
+    // [END createSink]
+    return sink;
+  }
+
+  /**
+   * Example of asynchronously creating a sink to export logs to a BigQuery dataset (in the
+   * {@link LoggingOptions#projectId()} project).
+   */
+  // [TARGET createAsync(SinkInfo)]
+  // [VARIABLE "my_sink_name"]
+  // [VARIABLE "my_dataset"]
+  public Sink createSinkAsync(String sinkName, String datasetName)
+      throws ExecutionException, InterruptedException {
+    // [START createSinkAsync]
+    SinkInfo sinkInfo = SinkInfo.of(sinkName, DatasetDestination.of(datasetName));
+    Future<Sink> future = logging.createAsync(sinkInfo);
+    // ...
+    Sink sink = future.get();
+    // [END createSinkAsync]
+    return sink;
+  }
+
+  /**
+   * Example of updating a sink.
+   */
+  // [TARGET update(SinkInfo)]
+  // [VARIABLE "my_sink_name"]
+  // [VARIABLE "my_dataset"]
+  public Sink updateSink(String sinkName, String datasetName) {
+    // [START updateSink]
+    SinkInfo sinkInfo = SinkInfo.builder(sinkName, DatasetDestination.of(datasetName))
+        .versionFormat(SinkInfo.VersionFormat.V2)
+        .filter("severity>=ERROR")
+        .build();
+    Sink sink = logging.update(sinkInfo);
+    // [END updateSink]
+    return sink;
+  }
+
+  /**
+   * Example of asynchronously updating a sink.
+   */
+  // [TARGET updateAsync(SinkInfo)]
+  // [VARIABLE "my_sink_name"]
+  // [VARIABLE "my_dataset"]
+  public Sink updateSinkAsync(String sinkName, String datasetName)
+      throws ExecutionException, InterruptedException {
+    // [START updateSinkAsync]
+    SinkInfo sinkInfo = SinkInfo.builder(sinkName, DatasetDestination.of(datasetName))
+        .versionFormat(SinkInfo.VersionFormat.V2)
+        .filter("severity>=ERROR")
+        .build();
+    Future<Sink> future = logging.updateAsync(sinkInfo);
+    // ...
+    Sink sink = future.get();
+    // [END updateSinkAsync]
+    return sink;
+  }
+
+  /**
+   * Example of getting a sink.
+   */
+  // [TARGET getSink(String)]
+  // [VARIABLE "my_sink_name"]
+  public Sink getSink(String sinkName) {
+    // [START getSink]
+    Sink sink = logging.getSink(sinkName);
+    if (sink != null) {
+      // sink was not found
+    }
+    // [END getSink]
+    return sink;
+  }
+
+  /**
+   * Example of asynchronously getting a sink.
+   */
+  // [TARGET getSinkAsync(String)]
+  // [VARIABLE "my_sink_name"]
+  public Sink getSinkAsync(String sinkName) throws ExecutionException, InterruptedException {
+    // [START getSinkAsync]
+    Future<Sink> future = logging.getSinkAsync(sinkName);
+    // ...
+    Sink sink = future.get();
+    if (sink != null) {
+      // sink was not found
+    }
+    // [END getSinkAsync]
+    return sink;
+  }
+
+  /**
+   * Example of listing sinks, specifying the page size.
+   */
+  // [TARGET listSinks(ListOption...)]
+  public Page<Sink> listSinks() {
+    // [START listSinks]
+    Page<Sink> sinks = logging.listSinks(ListOption.pageSize(100));
+    Iterator<Sink> sinkIterator = sinks.iterateAll();
+    while (sinkIterator.hasNext()) {
+      Sink sink = sinkIterator.next();
+      // do something with the sink
+    }
+    // [END listSinks]
+    return sinks;
+  }
+
+  /**
+   * Example of asynchronously listing sinks, specifying the page size.
+   */
+  // [TARGET listSinksAsync(ListOption...)]
+  public Page<Sink> listSinksAsync() throws ExecutionException, InterruptedException {
+    // [START listSinksAsync]
+    Future<AsyncPage<Sink>> future = logging.listSinksAsync(ListOption.pageSize(100));
+    // ...
+    AsyncPage<Sink> sinks = future.get();
+    Iterator<Sink> sinkIterator = sinks.iterateAll();
+    while (sinkIterator.hasNext()) {
+      Sink sink = sinkIterator.next();
+      // do something with the sink
+    }
+    // [END listSinksAsync]
+    return sinks;
+  }
+
+  /**
+   * Example of deleting a sink.
+   */
+  // [TARGET deleteSink(String)]
+  // [VARIABLE "my_sink_name"]
+  public boolean deleteSink(String sinkName) {
+    // [START deleteSink]
+    boolean deleted = logging.deleteSink(sinkName);
+    if (deleted) {
+      // the sink was deleted
+    } else {
+      // the sink was not found
+    }
+    // [END deleteSink]
+    return deleted;
+  }
+
+  /**
+   * Example of asynchronously deleting a sink.
+   */
+  // [TARGET deleteSinkAsync(String)]
+  // [VARIABLE "my_sink_name"]
+  public boolean deleteSinkAsync(String sinkName) throws ExecutionException, InterruptedException {
+    // [START deleteSinkAsync]
+    Future<Boolean> future = logging.deleteSinkAsync(sinkName);
+    // ...
+    boolean deleted = future.get();
+    if (deleted) {
+      // the sink was deleted
+    } else {
+      // the sink was not found
+    }
+    // [END deleteSinkAsync]
+    return deleted;
+  }
+
+  /**
+   * Example of deleting a log.
+   */
+  // [TARGET deleteLog(String)]
+  // [VARIABLE "my_log_name"]
+  public boolean deleteLog(String logName) {
+    // [START deleteLog]
+    boolean deleted = logging.deleteLog(logName);
+    if (deleted) {
+      // the log was deleted
+    } else {
+      // the log was not found
+    }
+    // [END deleteLog]
+    return deleted;
+  }
+
+  /**
+   * Example of asynchronously deleting a log.
+   */
+  // [TARGET deleteLogAsync(String)]
+  // [VARIABLE "my_log_name"]
+  public boolean deleteLogAsync(String logName) throws ExecutionException, InterruptedException {
+    // [START deleteLogAsync]
+    Future<Boolean> future = logging.deleteLogAsync(logName);
+    // ...
+    boolean deleted = future.get();
+    if (deleted) {
+      // the log was deleted
+    } else {
+      // the log was not found
+    }
+    // [END deleteLogAsync]
+    return deleted;
+  }
+
+  /**
+   * Example of listing monitored resource descriptors, specifying the page size.
+   */
+  // [TARGET listMonitoredResourceDescriptors(ListOption...)]
+  public Page<MonitoredResourceDescriptor> listMonitoredResourceDescriptors() {
+    // [START listMonitoredResourceDescriptors]
+    Page<MonitoredResourceDescriptor> descriptors =
+        logging.listMonitoredResourceDescriptors(ListOption.pageSize(100));
+    Iterator<MonitoredResourceDescriptor> descriptorIterator = descriptors.iterateAll();
+    while (descriptorIterator.hasNext()) {
+      MonitoredResourceDescriptor descriptor = descriptorIterator.next();
+      // do something with the descriptor
+    }
+    // [END listMonitoredResourceDescriptors]
+    return descriptors;
+  }
+
+  /**
+   * Example of asynchronously listing monitored resource descriptors, specifying the page size.
+   */
+  // [TARGET listMonitoredResourceDescriptorsAsync(ListOption...)]
+  public Page<MonitoredResourceDescriptor> listMonitoredResourceDescriptorsAsync()
+      throws ExecutionException, InterruptedException {
+    // [START listMonitoredResourceDescriptorsAsync]
+    Future<AsyncPage<MonitoredResourceDescriptor>> future =
+        logging.listMonitoredResourceDescriptorsAsync(ListOption.pageSize(100));
+    // ...
+    AsyncPage<MonitoredResourceDescriptor> descriptors = future.get();
+    Iterator<MonitoredResourceDescriptor> descriptorIterator = descriptors.iterateAll();
+    while (descriptorIterator.hasNext()) {
+      MonitoredResourceDescriptor descriptor = descriptorIterator.next();
+      // do something with the descriptor
+    }
+    // [END listMonitoredResourceDescriptorsAsync]
+    return descriptors;
+  }
+
+  /**
+   * Example of creating a metric for logs with severity higher or equal to ERROR.
+   */
+  // [TARGET create(MetricInfo)]
+  // [VARIABLE "my_metric_name"]
+  public Metric createMetric(String metricName) {
+    // [START createMetric]
+    MetricInfo metricInfo = MetricInfo.of(metricName, "severity>=ERROR");
+    Metric metric = logging.create(metricInfo);
+    // [END createMetric]
+    return metric;
+  }
+
+  /**
+   * Example of asynchronously creating a metric for logs with severity higher or equal to ERROR.
+   */
+  // [TARGET createAsync(MetricInfo)]
+  // [VARIABLE "my_metric_name"]
+  public Metric createMetricAsync(String metricName)
+      throws ExecutionException, InterruptedException {
+    // [START createMetricAsync]
+    MetricInfo metricInfo = MetricInfo.of(metricName, "severity>=ERROR");
+    Future<Metric> future = logging.createAsync(metricInfo);
+    // ...
+    Metric metric = future.get();
+    // [END createMetricAsync]
+    return metric;
+  }
+
+  /**
+   * Example of updating a metric.
+   */
+  // [TARGET update(MetricInfo)]
+  // [VARIABLE "my_metric_name"]
+  public Metric updateMetric(String metricName) {
+    // [START updateMetric]
+    MetricInfo metricInfo = MetricInfo.builder(metricName, "severity>=ERROR")
+        .description("new description")
+        .build();
+    Metric metric = logging.update(metricInfo);
+    // [END updateMetric]
+    return metric;
+  }
+
+  /**
+   * Example of asynchronously updating a metric.
+   */
+  // [TARGET updateAsync(MetricInfo)]
+  // [VARIABLE "my_metric_name"]
+  public Metric updateMetricAsync(String metricName)
+      throws ExecutionException, InterruptedException {
+    // [START updateMetricAsync]
+    MetricInfo metricInfo = MetricInfo.builder(metricName, "severity>=ERROR")
+        .description("new description")
+        .build();
+    Future<Metric> future = logging.updateAsync(metricInfo);
+    // ...
+    Metric metric = future.get();
+    // [END updateMetricAsync]
+    return metric;
+  }
+
+  /**
+   * Example of getting a metric.
+   */
+  // [TARGET getMetric(String)]
+  // [VARIABLE "my_metric_name"]
+  public Metric getMetric(String metricName) {
+    // [START getMetric]
+    Metric metric = logging.getMetric(metricName);
+    if (metric != null) {
+      // metric was not found
+    }
+    // [END getMetric]
+    return metric;
+  }
+
+  /**
+   * Example of asynchronously getting a metric.
+   */
+  // [TARGET getMetricAsync(String)]
+  // [VARIABLE "my_metric_name"]
+  public Metric getMetricAsync(String metricName) throws ExecutionException, InterruptedException {
+    // [START getMetricAsync]
+    Future<Metric> future = logging.getMetricAsync(metricName);
+    // ...
+    Metric metric = future.get();
+    if (metric != null) {
+      // metric was not found
+    }
+    // [END getMetricAsync]
+    return metric;
+  }
+
+  /**
+   * Example of listing metrics, specifying the page size.
+   */
+  // [TARGET listMetrics(ListOption...)]
+  public Page<Metric> listMetrics() {
+    // [START listMetrics]
+    Page<Metric> metrics = logging.listMetrics(ListOption.pageSize(100));
+    Iterator<Metric> metricIterator = metrics.iterateAll();
+    while (metricIterator.hasNext()) {
+      Metric metric = metricIterator.next();
+      // do something with the metric
+    }
+    // [END listMetrics]
+    return metrics;
+  }
+
+  /**
+   * Example of asynchronously listing metrics, specifying the page size.
+   */
+  // [TARGET listMetricsAsync(ListOption...)]
+  public Page<Metric> listMetricsAsync() throws ExecutionException, InterruptedException {
+    // [START listMetricsAsync]
+    Future<AsyncPage<Metric>> future = logging.listMetricsAsync(ListOption.pageSize(100));
+    // ...
+    AsyncPage<Metric> metrics = future.get();
+    Iterator<Metric> metricIterator = metrics.iterateAll();
+    while (metricIterator.hasNext()) {
+      Metric metric = metricIterator.next();
+      // do something with the metric
+    }
+    // [END listMetricsAsync]
+    return metrics;
+  }
+
+  /**
+   * Example of deleting a metric.
+   */
+  // [TARGET deleteMetric(String)]
+  // [VARIABLE "my_metric_name"]
+  public boolean deleteMetric(String metricName) {
+    // [START deleteMetric]
+    boolean deleted = logging.deleteMetric(metricName);
+    if (deleted) {
+      // the metric was deleted
+    } else {
+      // the metric was not found
+    }
+    // [END deleteMetric]
+    return deleted;
+  }
+
+  /**
+   * Example of asynchronously deleting a metric.
+   */
+  // [TARGET deleteMetricAsync(String)]
+  // [VARIABLE "my_metric_name"]
+  public boolean deleteMetricAsync(String metricName)
+      throws ExecutionException, InterruptedException {
+    // [START deleteMetricAsync]
+    Future<Boolean> future = logging.deleteMetricAsync(metricName);
+    // ...
+    boolean deleted = future.get();
+    if (deleted) {
+      // the metric was deleted
+    } else {
+      // the metric was not found
+    }
+    // [END deleteMetricAsync]
+    return deleted;
+  }
+
+  /**
+   * Example of writing log entries and providing a default log name and monitored resource.
+   */
+  // [TARGET write(Iterable, WriteOption...)]
+  // [VARIABLE "my_log_name"]
+  public void write(String logName) {
+    // [START write]
+    List<LogEntry> entries = new ArrayList<>();
+    entries.add(LogEntry.of(StringPayload.of("Entry payload")));
+    Map<String, Object> jsonMap = new HashMap<>();
+    jsonMap.put("key", "value");
+    entries.add(LogEntry.of(JsonPayload.of(jsonMap)));
+    logging.write(entries,
+        WriteOption.logName(logName),
+        WriteOption.resource(MonitoredResource.builder("global").build()));
+    // [END write]
+  }
+
+  /**
+   * Example of asynchronously writing log entries and providing a default log name and monitored
+   * resource.
+   */
+  // [TARGET writeAsync(Iterable, WriteOption...)]
+  // [VARIABLE "my_log_name"]
+  public Future<Void> writeAsync(String logName) {
+    // [START writeAsync]
+    List<LogEntry> entries = new ArrayList<>();
+    entries.add(LogEntry.of(StringPayload.of("Entry payload")));
+    Map<String, Object> jsonMap = new HashMap<>();
+    jsonMap.put("key", "value");
+    entries.add(LogEntry.of(JsonPayload.of(jsonMap)));
+    Future<Void> future = logging.writeAsync(
+        entries,
+        WriteOption.logName(logName),
+        WriteOption.resource(MonitoredResource.builder("global").build()));
+    // [END writeAsync]
+    return future;
+  }
+
+  /**
+   * Example of listing log entries for a specific log.
+   */
+  // [TARGET listLogEntries(EntryListOption...)]
+  // [VARIABLE "logName=projects/my_project_id/logs/my_log_name"]
+  public Page<LogEntry> listLogEntries(String filter) {
+    // [START listLogEntries]
+    Page<LogEntry> entries = logging.listLogEntries(EntryListOption.filter(filter));
+    Iterator<LogEntry> entryIterator = entries.iterateAll();
+    while (entryIterator.hasNext()) {
+      LogEntry entry = entryIterator.next();
+      // do something with the entry
+    }
+    // [END listLogEntries]
+    return entries;
+  }
+
+  /**
+   * Example of asynchronously listing log entries for a specific log.
+   */
+  // [TARGET listLogEntriesAsync(EntryListOption...)]
+  // [VARIABLE "logName=projects/my_project_id/logs/my_log_name"]
+  public Page<LogEntry> listLogEntriesAsync(String filter)
+      throws ExecutionException, InterruptedException {
+    // [START listLogEntriesAsync]
+    Future<AsyncPage<LogEntry>> future =
+        logging.listLogEntriesAsync(EntryListOption.filter(filter));
+    // ...
+    AsyncPage<LogEntry> entries = future.get();
+    Iterator<LogEntry> entryIterator = entries.iterateAll();
+    while (entryIterator.hasNext()) {
+      LogEntry entry = entryIterator.next();
+      // do something with the entry
+    }
+    // [END listLogEntriesAsync]
+    return entries;
+  }
+}
diff --git a/gcloud-java-examples/src/test/java/com/google/cloud/examples/logging/snippets/ITLoggingSnippets.java b/gcloud-java-examples/src/test/java/com/google/cloud/examples/logging/snippets/ITLoggingSnippets.java
new file mode 100644
index 000000000000..dea50e532726
--- /dev/null
+++ b/gcloud-java-examples/src/test/java/com/google/cloud/examples/logging/snippets/ITLoggingSnippets.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+package com.google.cloud.examples.logging.snippets;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.cloud.MonitoredResourceDescriptor;
+import com.google.cloud.logging.LogEntry;
+import com.google.cloud.logging.Logging;
+import com.google.cloud.logging.Metric;
+import com.google.cloud.logging.Sink;
+import com.google.cloud.logging.testing.RemoteLoggingHelper;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.Timeout;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+public class ITLoggingSnippets {
+
+  private static final String DATASET = "dataset";
+  private static final Set<String> DESCRIPTOR_TYPES = ImmutableSet.of("gce_instance", "gae_app",
+      "cloudsql_database", "api", "gcs_bucket", "global", "dataflow_step", "build",
+      "app_script_function", "dataproc_cluster", "ml_job", "bigquery_resource",
+      "crm_iam_policy_check", "container", "gke_cluster", "cloud_debugger_resource",
+      "http_load_balancer", "aws_ec2_instance", "client_auth_config_brand",
+      "client_auth_config_client", "logging_log", "logging_sink", "metric", "project",
+      "testservice_matrix", "service_account", "deployment", "dns_managed_zone");
+
+  private static Logging logging;
+  private static LoggingSnippets loggingSnippets;
+
+  @Rule
+  public Timeout globalTimeout = Timeout.seconds(300);
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @BeforeClass
+  public static void beforeClass() {
+    RemoteLoggingHelper helper = RemoteLoggingHelper.create();
+    logging = helper.options().service();
+    loggingSnippets = new LoggingSnippets(logging);
+  }
+
+  @Test
+  public void testSink() throws ExecutionException, InterruptedException {
+    String sinkName1 = RemoteLoggingHelper.formatForTest("sink_name1");
+    String sinkName2 = RemoteLoggingHelper.formatForTest("sink_name2");
+    Sink sink1 = loggingSnippets.createSink(sinkName1, DATASET);
+    Sink sink2 = loggingSnippets.createSinkAsync(sinkName2, DATASET);
+    assertNotNull(sink1);
+    assertNotNull(sink2);
+    sink1 = loggingSnippets.getSink(sinkName1);
+    sink2 = loggingSnippets.getSinkAsync(sinkName2);
+    assertNotNull(sink1);
+    assertNotNull(sink2);
+    sink1 = loggingSnippets.updateSink(sinkName1, DATASET);
+    sink2 = loggingSnippets.updateSinkAsync(sinkName2, DATASET);
+    Set<Sink> sinks = Sets.newHashSet(loggingSnippets.listSinks().iterateAll());
+    while (!sinks.contains(sink1) || !sinks.contains(sink2)) {
+      Thread.sleep(500);
+      sinks = Sets.newHashSet(loggingSnippets.listSinks().iterateAll());
+    }
+    sinks = Sets.newHashSet(loggingSnippets.listSinksAsync().iterateAll());
+    while (!sinks.contains(sink1) || !sinks.contains(sink2)) {
+      Thread.sleep(500);
+      sinks = Sets.newHashSet(loggingSnippets.listSinksAsync().iterateAll());
+    }
+    assertTrue(loggingSnippets.deleteSink(sinkName1));
+    assertTrue(loggingSnippets.deleteSinkAsync(sinkName2));
+  }
+
+  @Test
+  public void testMetric() throws ExecutionException, InterruptedException {
+    String metricName1 = RemoteLoggingHelper.formatForTest("metric_name1");
+    String metricName2 = RemoteLoggingHelper.formatForTest("metric_name2");
+    Metric metric1 = loggingSnippets.createMetric(metricName1);
+    Metric metric2 = loggingSnippets.createMetricAsync(metricName2);
+    assertNotNull(metric1);
+    assertNotNull(metric2);
+    metric1 = loggingSnippets.getMetric(metricName1);
+    metric2 = loggingSnippets.getMetricAsync(metricName2);
+    assertNotNull(metric1);
+    assertNotNull(metric2);
+    metric1 = loggingSnippets.updateMetric(metricName1);
+    metric2 = loggingSnippets.updateMetricAsync(metricName2);
+    Set<Metric> metrics = Sets.newHashSet(loggingSnippets.listMetrics().iterateAll());
+    while (!metrics.contains(metric1) || !metrics.contains(metric2)) {
+      Thread.sleep(500);
+      metrics = Sets.newHashSet(loggingSnippets.listMetrics().iterateAll());
+    }
+    metrics = Sets.newHashSet(loggingSnippets.listMetricsAsync().iterateAll());
+    while (!metrics.contains(metric1) || !metrics.contains(metric2)) {
+      Thread.sleep(500);
+      metrics = Sets.newHashSet(loggingSnippets.listMetricsAsync().iterateAll());
+    }
+    assertTrue(loggingSnippets.deleteMetric(metricName1));
+    assertTrue(loggingSnippets.deleteMetricAsync(metricName2));
+  }
+
+  @Test
+  public void testMonitoredResourceDescriptor() throws ExecutionException, InterruptedException {
+    Iterator<MonitoredResourceDescriptor> iterator =
+        loggingSnippets.listMonitoredResourceDescriptors().iterateAll();
+    Set<String> descriptorTypes = new HashSet<>();
+    while (iterator.hasNext()) {
+      descriptorTypes.add(iterator.next().type());
+    }
+    for (String type : DESCRIPTOR_TYPES) {
+      assertTrue(descriptorTypes.contains(type));
+    }
+    iterator = loggingSnippets.listMonitoredResourceDescriptorsAsync().iterateAll();
+    descriptorTypes.clear();
+    while (iterator.hasNext()) {
+      descriptorTypes.add(iterator.next().type());
+    }
+    for (String type : DESCRIPTOR_TYPES) {
+      assertTrue(descriptorTypes.contains(type));
+    }
+  }
+
+  @Test
+  public void testWriteAndListLogEntries() throws InterruptedException {
+    String logName = RemoteLoggingHelper.formatForTest("log_name");
+    String filter = "logName=projects/" + logging.options().projectId() + "/logs/" + logName;
+    loggingSnippets.write(logName);
+    Iterator<LogEntry> iterator = loggingSnippets.listLogEntries(filter).iterateAll();
+    while (Iterators.size(iterator) < 2) {
+      Thread.sleep(500);
+      iterator = loggingSnippets.listLogEntries(filter).iterateAll();
+    }
+    assertTrue(loggingSnippets.deleteLog(logName));
+  }
+
+  @Test
+  public void testWriteAndListLogEntriesAsync() throws ExecutionException, InterruptedException {
+    String logName = RemoteLoggingHelper.formatForTest("log_name");
+    String filter = "logName=projects/" + logging.options().projectId() + "/logs/" + logName;
+    loggingSnippets.writeAsync(logName).get();
+    Iterator<LogEntry> iterator = loggingSnippets.listLogEntriesAsync(filter).iterateAll();
+    while (Iterators.size(iterator) < 2) {
+      Thread.sleep(500);
+      iterator = loggingSnippets.listLogEntriesAsync(filter).iterateAll();
+    }
+    assertTrue(loggingSnippets.deleteLogAsync(logName));
+  }
+}
diff --git a/gcloud-java-logging/src/main/java/com/google/cloud/logging/Logging.java b/gcloud-java-logging/src/main/java/com/google/cloud/logging/Logging.java
index 454590aacd7d..2f4b9c0b1cb7 100644
--- a/gcloud-java-logging/src/main/java/com/google/cloud/logging/Logging.java
+++ b/gcloud-java-logging/src/main/java/com/google/cloud/logging/Logging.java
@@ -195,6 +195,15 @@ public static EntryListOption filter(String filter) {
   /**
    * Creates a new sink.
    *
+   * <p>Example of creating a sink to export logs to a BigQuery dataset (in the
+   * {@link LoggingOptions#projectId()} project).
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * String datasetName = "my_dataset";
+   * SinkInfo sinkInfo = SinkInfo.of(sinkName, DatasetDestination.of(datasetName));
+   * Sink sink = logging.create(sinkInfo);
+   * }</pre>
+   *
    * @return the created sink
    * @throws LoggingException upon failure
    */
@@ -203,12 +212,35 @@ public static EntryListOption filter(String filter) {
   /**
    * Sends a request for creating a sink. This method returns a {@code Future} object to consume the
    * result. {@link Future#get()} returns the created sink.
+   *
+   * <p>Example of asynchronously creating a sink to export logs to a BigQuery dataset (in the
+   * {@link LoggingOptions#projectId()} project).
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * String datasetName = "my_dataset";
+   * SinkInfo sinkInfo = SinkInfo.of(sinkName, DatasetDestination.of(datasetName));
+   * Future<Sink> future = logging.createAsync(sinkInfo);
+   * // ...
+   * Sink sink = future.get();
+   * }</pre>
+   *
    */
   Future<Sink> createAsync(SinkInfo sink);
 
   /**
    * Updates a sink or creates one if it does not exist.
    *
+   * <p>Example of updating a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * String datasetName = "my_dataset";
+   * SinkInfo sinkInfo = SinkInfo.builder(sinkName, DatasetDestination.of(datasetName))
+   *     .versionFormat(SinkInfo.VersionFormat.V2)
+   *     .filter("severity>=ERROR")
+   *     .build();
+   * Sink sink = logging.update(sinkInfo);
+   * }</pre>
+   *
    * @return the created sink
    * @throws LoggingException upon failure
    */
@@ -218,12 +250,35 @@ public static EntryListOption filter(String filter) {
    * Sends a request for updating a sink (or creating it, if it does not exist). This method returns
    * a {@code Future} object to consume the result. {@link Future#get()} returns the
    * updated/created sink or {@code null} if not found.
+   *
+   * <p>Example of asynchronously updating a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * String datasetName = "my_dataset";
+   * SinkInfo sinkInfo = SinkInfo.builder(sinkName, DatasetDestination.of(datasetName))
+   *     .versionFormat(SinkInfo.VersionFormat.V2)
+   *     .filter("severity>=ERROR")
+   *     .build();
+   * Future<Sink> future = logging.updateAsync(sinkInfo);
+   * // ...
+   * Sink sink = future.get();
+   * }</pre>
+   *
    */
   Future<Sink> updateAsync(SinkInfo sink);
 
   /**
    * Returns the requested sink or {@code null} if not found.
    *
+   * <p>Example of getting a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * Sink sink = logging.getSink(sinkName);
+   * if (sink != null) {
+   *   // sink was not found
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Sink getSink(String sink);
@@ -232,6 +287,17 @@ public static EntryListOption filter(String filter) {
    * Sends a request for getting a sink. This method returns a {@code Future} object to consume the
    * result. {@link Future#get()} returns the requested sink or {@code null} if not found.
    *
+   * <p>Example of asynchronously getting a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * Future<Sink> future = logging.getSinkAsync(sinkName);
+   * // ...
+   * Sink sink = future.get();
+   * if (sink != null) {
+   *   // sink was not found
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Future<Sink> getSinkAsync(String sink);
@@ -241,6 +307,16 @@ public static EntryListOption filter(String filter) {
    * paginated results. Use {@link ListOption} to specify the page size or the page token from which
    * to start listing sinks.
    *
+   * <p>Example of listing sinks, specifying the page size.
+   * <pre> {@code
+   * Page<Sink> sinks = logging.listSinks(ListOption.pageSize(100));
+   * Iterator<Sink> sinkIterator = sinks.iterateAll();
+   * while (sinkIterator.hasNext()) {
+   *   Sink sink = sinkIterator.next();
+   *   // do something with the sink
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Page<Sink> listSinks(ListOption... options);
@@ -250,12 +326,36 @@ public static EntryListOption filter(String filter) {
    * the result. {@link Future#get()} returns an {@link AsyncPage} object that can be used to
    * asynchronously handle paginated results. Use {@link ListOption} to specify the page size or the
    * page token from which to start listing sinks.
+   *
+   * <p>Example of asynchronously listing sinks, specifying the page size.
+   * <pre> {@code
+   * Future<AsyncPage<Sink>> future = logging.listSinksAsync(ListOption.pageSize(100));
+   * // ...
+   * AsyncPage<Sink> sinks = future.get();
+   * Iterator<Sink> sinkIterator = sinks.iterateAll();
+   * while (sinkIterator.hasNext()) {
+   *   Sink sink = sinkIterator.next();
+   *   // do something with the sink
+   * }
+   * }</pre>
+   *
    */
   Future<AsyncPage<Sink>> listSinksAsync(ListOption... options);
 
   /**
    * Deletes the requested sink.
    *
+   * <p>Example of deleting a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * boolean deleted = logging.deleteSink(sinkName);
+   * if (deleted) {
+   *   // the sink was deleted
+   * } else {
+   *   // the sink was not found
+   * }
+   * }</pre>
+   *
    * @return {@code true} if the sink was deleted, {@code false} if it was not found
    */
   boolean deleteSink(String sink);
@@ -264,12 +364,37 @@ public static EntryListOption filter(String filter) {
    * Sends a request for deleting a sink. This method returns a {@code Future} object to consume the
    * result. {@link Future#get()} returns {@code true} if the sink was deleted, {@code false} if it
    * was not found.
+   *
+   * <p>Example of asynchronously deleting a sink.
+   * <pre> {@code
+   * String sinkName = "my_sink_name";
+   * Future<Boolean> future = logging.deleteSinkAsync(sinkName);
+   * // ...
+   * boolean deleted = future.get();
+   * if (deleted) {
+   *   // the sink was deleted
+   * } else {
+   *   // the sink was not found
+   * }
+   * }</pre>
+   *
    */
   Future<Boolean> deleteSinkAsync(String sink);
 
   /**
    * Deletes a log and all its log entries. The log will reappear if new entries are written to it.
    *
+   * <p>Example of deleting a log.
+   * <pre> {@code
+   * String logName = "my_log_name";
+   * boolean deleted = logging.deleteLog(logName);
+   * if (deleted) {
+   *   // the log was deleted
+   * } else {
+   *   // the log was not found
+   * }
+   * }</pre>
+   *
    * @return {@code true} if the log was deleted, {@code false} if it was not found
    */
   boolean deleteLog(String log);
@@ -278,6 +403,20 @@ public static EntryListOption filter(String filter) {
    * Sends a request for deleting a log and all its log entries. This method returns a
    * {@code Future} object to consume the result. {@link Future#get()} returns {@code true} if the
    * log was deleted, {@code false} if it was not found.
+   *
+   * <p>Example of asynchronously deleting a log.
+   * <pre> {@code
+   * String logName = "my_log_name";
+   * Future<Boolean> future = logging.deleteLogAsync(logName);
+   * // ...
+   * boolean deleted = future.get();
+   * if (deleted) {
+   *   // the log was deleted
+   * } else {
+   *   // the log was not found
+   * }
+   * }</pre>
+   *
    */
   Future<Boolean> deleteLogAsync(String log);
 
@@ -286,6 +425,17 @@ public static EntryListOption filter(String filter) {
    * {@link Page} object that can be used to consume paginated results. Use {@link ListOption} to
    * specify the page size or the page token from which to start listing resource descriptors.
    *
+   * <p>Example of listing monitored resource descriptors, specifying the page size.
+   * <pre> {@code
+   * Page<MonitoredResourceDescriptor> descriptors =
+   *     logging.listMonitoredResourceDescriptors(ListOption.pageSize(100));
+   * Iterator<MonitoredResourceDescriptor> descriptorIterator = descriptors.iterateAll();
+   * while (descriptorIterator.hasNext()) {
+   *   MonitoredResourceDescriptor descriptor = descriptorIterator.next();
+   *   // do something with the descriptor
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Page<MonitoredResourceDescriptor> listMonitoredResourceDescriptors(ListOption... options);
@@ -296,6 +446,20 @@ public static EntryListOption filter(String filter) {
    * {@link AsyncPage} object that can be used to asynchronously handle paginated results. Use
    * {@link ListOption} to specify the page size or the page token from which to start listing
    * resource descriptors.
+   *
+   * <p>Example of asynchronously listing monitored resource descriptors, specifying the page size.
+   * <pre> {@code
+   * Future<AsyncPage<MonitoredResourceDescriptor>> future =
+   *     logging.listMonitoredResourceDescriptorsAsync(ListOption.pageSize(100));
+   * // ...
+   * AsyncPage<MonitoredResourceDescriptor> descriptors = future.get();
+   * Iterator<MonitoredResourceDescriptor> descriptorIterator = descriptors.iterateAll();
+   * while (descriptorIterator.hasNext()) {
+   *   MonitoredResourceDescriptor descriptor = descriptorIterator.next();
+   *   // do something with the descriptor
+   * }
+   * }</pre>
+   *
    */
   Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsAsync(
       ListOption... options);
@@ -303,6 +467,13 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
   /**
    * Creates a new metric.
    *
+   * <p>Example of creating a metric for logs with severity higher or equal to ERROR.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * MetricInfo metricInfo = MetricInfo.of(metricName, "severity>=ERROR");
+   * Metric metric = logging.create(metricInfo);
+   * }</pre>
+   *
    * @return the created metric
    * @throws LoggingException upon failure
    */
@@ -311,12 +482,31 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
   /**
    * Sends a request for creating a metric. This method returns a {@code Future} object to consume
    * the result. {@link Future#get()} returns the created metric.
+   *
+   * <p>Example of asynchronously creating a metric for logs with severity higher or equal to ERROR.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * MetricInfo metricInfo = MetricInfo.of(metricName, "severity>=ERROR");
+   * Future<Metric> future = logging.createAsync(metricInfo);
+   * // ...
+   * Metric metric = future.get();
+   * }</pre>
+   *
    */
   Future<Metric> createAsync(MetricInfo metric);
 
   /**
    * Updates a metric or creates one if it does not exist.
    *
+   * <p>Example of updating a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * MetricInfo metricInfo = MetricInfo.builder(metricName, "severity>=ERROR")
+   *     .description("new description")
+   *     .build();
+   * Metric metric = logging.update(metricInfo);
+   * }</pre>
+   *
    * @return the created metric
    * @throws LoggingException upon failure
    */
@@ -326,12 +516,33 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * Sends a request for updating a metric (or creating it, if it does not exist). This method
    * returns a {@code Future} object to consume the result. {@link Future#get()} returns the
    * updated/created metric or {@code null} if not found.
+   *
+   * <p>Example of asynchronously updating a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * MetricInfo metricInfo = MetricInfo.builder(metricName, "severity>=ERROR")
+   *     .description("new description")
+   *     .build();
+   * Future<Metric> future = logging.updateAsync(metricInfo);
+   * // ...
+   * Metric metric = future.get();
+   * }</pre>
+   *
    */
   Future<Metric> updateAsync(MetricInfo metric);
 
   /**
    * Returns the requested metric or {@code null} if not found.
    *
+   * <p>Example of getting a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * Metric metric = logging.getMetric(metricName);
+   * if (metric != null) {
+   *   // metric was not found
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Metric getMetric(String metric);
@@ -340,6 +551,17 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * Sends a request for getting a metric. This method returns a {@code Future} object to consume
    * the result. {@link Future#get()} returns the requested metric or {@code null} if not found.
    *
+   * <p>Example of asynchronously getting a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * Future<Metric> future = logging.getMetricAsync(metricName);
+   * // ...
+   * Metric metric = future.get();
+   * if (metric != null) {
+   *   // metric was not found
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Future<Metric> getMetricAsync(String metric);
@@ -349,6 +571,16 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * paginated results. Use {@link ListOption} to specify the page size or the page token from which
    * to start listing metrics.
    *
+   * <p>Example of listing metrics, specifying the page size.
+   * <pre> {@code
+   * Page<Metric> metrics = logging.listMetrics(ListOption.pageSize(100));
+   * Iterator<Metric> metricIterator = metrics.iterateAll();
+   * while (metricIterator.hasNext()) {
+   *   Metric metric = metricIterator.next();
+   *   // do something with the metric
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Page<Metric> listMetrics(ListOption... options);
@@ -358,12 +590,36 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * the result. {@link Future#get()} returns an {@link AsyncPage} object that can be used to
    * asynchronously handle paginated results. Use {@link ListOption} to specify the page size or the
    * page token from which to start listing metrics.
+   *
+   * <p>Example of asynchronously listing metrics, specifying the page size.
+   * <pre> {@code
+   * Future<AsyncPage<Metric>> future = logging.listMetricsAsync(ListOption.pageSize(100));
+   * // ...
+   * AsyncPage<Metric> metrics = future.get();
+   * Iterator<Metric> metricIterator = metrics.iterateAll();
+   * while (metricIterator.hasNext()) {
+   *   Metric metric = metricIterator.next();
+   *   // do something with the metric
+   * }
+   * }</pre>
+   *
    */
   Future<AsyncPage<Metric>> listMetricsAsync(ListOption... options);
 
   /**
    * Deletes the requested metric.
    *
+   * <p>Example of deleting a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * boolean deleted = logging.deleteMetric(metricName);
+   * if (deleted) {
+   *   // the metric was deleted
+   * } else {
+   *   // the metric was not found
+   * }
+   * }</pre>
+   *
    * @return {@code true} if the metric was deleted, {@code false} if it was not found
    */
   boolean deleteMetric(String metric);
@@ -372,6 +628,20 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * Sends a request for deleting a metric. This method returns a {@code Future} object to consume
    * the result. {@link Future#get()} returns {@code true} if the metric was deleted, {@code false}
    * if it was not found.
+   *
+   * <p>Example of asynchronously deleting a metric.
+   * <pre> {@code
+   * String metricName = "my_metric_name";
+   * Future<Boolean> future = logging.deleteMetricAsync(metricName);
+   * // ...
+   * boolean deleted = future.get();
+   * if (deleted) {
+   *   // the metric was deleted
+   * } else {
+   *   // the metric was not found
+   * }
+   * }</pre>
+   *
    */
   Future<Boolean> deleteMetricAsync(String metric);
 
@@ -381,6 +651,20 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * {@link WriteOption#resource(MonitoredResource)} to provide a monitored resource for those
    * entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
    * to be added to every entry in {@code logEntries}.
+   *
+   * <p>Example of writing log entries and providing a default log name and monitored resource.
+   * <pre> {@code
+   * String logName = "my_log_name";
+   * List<LogEntry> entries = new ArrayList<>();
+   * entries.add(LogEntry.of(StringPayload.of("Entry payload")));
+   * Map<String, Object> jsonMap = new HashMap<>();
+   * jsonMap.put("key", "value");
+   * entries.add(LogEntry.of(JsonPayload.of(jsonMap)));
+   * logging.write(entries,
+   *     WriteOption.logName(logName),
+   *     WriteOption.resource(MonitoredResource.builder("global").build()));
+   * }</pre>
+   *
    */
   void write(Iterable<LogEntry> logEntries, WriteOption... options);
 
@@ -391,6 +675,22 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
    * to be added to every entry in {@code logEntries}. The method returns a {@code Future} object
    * that can be used to wait for the write operation to be completed.
+   *
+   * <p>Example of asynchronously writing log entries and providing a default log name and monitored
+   * resource.
+   * <pre> {@code
+   * String logName = "my_log_name";
+   * List<LogEntry> entries = new ArrayList<>();
+   * entries.add(LogEntry.of(StringPayload.of("Entry payload")));
+   * Map<String, Object> jsonMap = new HashMap<>();
+   * jsonMap.put("key", "value");
+   * entries.add(LogEntry.of(JsonPayload.of(jsonMap)));
+   * Future<Void> future = logging.writeAsync(
+   *     entries,
+   *     WriteOption.logName(logName),
+   *     WriteOption.resource(MonitoredResource.builder("global").build()));
+   * }</pre>
+   *
    */
   Future<Void> writeAsync(Iterable<LogEntry> logEntries, WriteOption... options);
 
@@ -402,6 +702,17 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * according to your preferred order (default is most-recent last). Use
    * {@link EntryListOption#filter(String)} to filter listed log entries.
    *
+   * <p>Example of listing log entries for a specific log.
+   * <pre> {@code
+   * String filter = "logName=projects/my_project_id/logs/my_log_name";
+   * Page<LogEntry> entries = logging.listLogEntries(EntryListOption.filter(filter));
+   * Iterator<LogEntry> entryIterator = entries.iterateAll();
+   * while (entryIterator.hasNext()) {
+   *   LogEntry entry = entryIterator.next();
+   *   // do something with the entry
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Page<LogEntry> listLogEntries(EntryListOption... options);
@@ -416,6 +727,20 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
    * your preferred order (default is most-recent last). Use {@link EntryListOption#filter(String)}
    * to filter listed log entries.
    *
+   * <p>Example of asynchronously listing log entries for a specific log.
+   * <pre> {@code
+   * String filter = "logName=projects/my_project_id/logs/my_log_name";
+   * Future<AsyncPage<LogEntry>> future =
+   *     logging.listLogEntriesAsync(EntryListOption.filter(filter));
+   * // ...
+   * AsyncPage<LogEntry> entries = future.get();
+   * Iterator<LogEntry> entryIterator = entries.iterateAll();
+   * while (entryIterator.hasNext()) {
+   *   LogEntry entry = entryIterator.next();
+   *   // do something with the entry
+   * }
+   * }</pre>
+   *
    * @throws LoggingException upon failure
    */
   Future<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... options);