aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/cloud.google.com/go/logging
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-06-13 19:31:19 +0200
committerGitHub <noreply@github.com>2017-06-13 19:31:19 +0200
commit5b060131006494cbc077f08b9b2fbf172f3eb239 (patch)
tree04f8586899db96f7fd8e7bc6a010fc10f1e2bb3b /vendor/cloud.google.com/go/logging
parentcd8e13f826ff24f5f8e0b8de1b9d3373aaf93d2f (diff)
parent612b82714b3e6660bf702f801ab96aacb3432e1f (diff)
Merge pull request #226 from google/dvyukov-vendor
vendor: vendor dependencies
Diffstat (limited to 'vendor/cloud.google.com/go/logging')
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/README.md11
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go66
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/config_client.go314
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go125
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/doc.go46
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/logging_client.go443
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go133
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/metrics_client.go301
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go125
-rw-r--r--vendor/cloud.google.com/go/logging/apiv2/mock_test.go1248
-rw-r--r--vendor/cloud.google.com/go/logging/doc.go90
-rw-r--r--vendor/cloud.google.com/go/logging/examples_test.go125
-rw-r--r--vendor/cloud.google.com/go/logging/internal/common.go39
-rw-r--r--vendor/cloud.google.com/go/logging/internal/testing/equal.go42
-rw-r--r--vendor/cloud.google.com/go/logging/internal/testing/fake.go418
-rw-r--r--vendor/cloud.google.com/go/logging/internal/testing/fake_test.go122
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go66
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go52
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go92
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go52
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go52
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/examples_test.go161
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/logadmin.go402
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go274
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/metrics.go154
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/metrics_test.go155
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/resources.go74
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/resources_test.go46
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/sinks.go169
-rw-r--r--vendor/cloud.google.com/go/logging/logadmin/sinks_test.go226
-rw-r--r--vendor/cloud.google.com/go/logging/logging.go738
-rw-r--r--vendor/cloud.google.com/go/logging/logging_test.go486
-rw-r--r--vendor/cloud.google.com/go/logging/logging_unexported_test.go228
33 files changed, 7075 insertions, 0 deletions
diff --git a/vendor/cloud.google.com/go/logging/apiv2/README.md b/vendor/cloud.google.com/go/logging/apiv2/README.md
new file mode 100644
index 000000000..d2d9a176e
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/README.md
@@ -0,0 +1,11 @@
+Auto-generated logging v2 clients
+=================================
+
+This package includes auto-generated clients for the logging v2 API.
+
+Use the handwritten logging client (in the parent directory,
+cloud.google.com/go/logging) in preference to this.
+
+This code is EXPERIMENTAL and subject to CHANGE AT ANY TIME.
+
+
diff --git a/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go b/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go
new file mode 100644
index 000000000..b4d91ab45
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go
@@ -0,0 +1,66 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging
+
+import (
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+import (
+ "strconv"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/internal/testutil"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+)
+
+var _ = iterator.Done
+var _ = strconv.FormatUint
+var _ = time.Now
+
+func TestLoggingServiceV2Smoke(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping smoke test in short mode")
+ }
+ ctx := context.Background()
+ ts := testutil.TokenSource(ctx, DefaultAuthScopes()...)
+ if ts == nil {
+ t.Skip("Integration tests skipped. See CONTRIBUTING.md for details")
+ }
+
+ projectId := testutil.ProjID()
+ _ = projectId
+
+ c, err := NewClient(ctx, option.WithTokenSource(ts))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var entries []*loggingpb.LogEntry = nil
+ var formattedLogName string = LoggingLogPath(projectId, "test-"+strconv.FormatInt(time.Now().UnixNano(), 10)+"")
+ var request = &loggingpb.WriteLogEntriesRequest{
+ Entries: entries,
+ LogName: formattedLogName,
+ }
+
+ if _, err := c.WriteLogEntries(ctx, request); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/config_client.go b/vendor/cloud.google.com/go/logging/apiv2/config_client.go
new file mode 100644
index 000000000..417769b09
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/config_client.go
@@ -0,0 +1,314 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging
+
+import (
+ "math"
+ "time"
+
+ "cloud.google.com/go/internal/version"
+ gax "github.com/googleapis/gax-go"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ "google.golang.org/api/transport"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+var (
+ configProjectPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
+ configSinkPathTemplate = gax.MustCompilePathTemplate("projects/{project}/sinks/{sink}")
+)
+
+// ConfigCallOptions contains the retry settings for each method of ConfigClient.
+type ConfigCallOptions struct {
+ ListSinks []gax.CallOption
+ GetSink []gax.CallOption
+ CreateSink []gax.CallOption
+ UpdateSink []gax.CallOption
+ DeleteSink []gax.CallOption
+}
+
+func defaultConfigClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ option.WithEndpoint("logging.googleapis.com:443"),
+ option.WithScopes(DefaultAuthScopes()...),
+ }
+}
+
+func defaultConfigCallOptions() *ConfigCallOptions {
+ retry := map[[2]string][]gax.CallOption{
+ {"default", "idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.DeadlineExceeded,
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ {"default", "non_idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ }
+ return &ConfigCallOptions{
+ ListSinks: retry[[2]string{"default", "idempotent"}],
+ GetSink: retry[[2]string{"default", "idempotent"}],
+ CreateSink: retry[[2]string{"default", "non_idempotent"}],
+ UpdateSink: retry[[2]string{"default", "non_idempotent"}],
+ DeleteSink: retry[[2]string{"default", "idempotent"}],
+ }
+}
+
+// ConfigClient is a client for interacting with Stackdriver Logging API.
+type ConfigClient struct {
+ // The connection to the service.
+ conn *grpc.ClientConn
+
+ // The gRPC API client.
+ configClient loggingpb.ConfigServiceV2Client
+
+ // The call options for this service.
+ CallOptions *ConfigCallOptions
+
+ // The metadata to be sent with each request.
+ xGoogHeader []string
+}
+
+// NewConfigClient creates a new config service v2 client.
+//
+// Service for configuring sinks used to export log entries outside of
+// Stackdriver Logging.
+func NewConfigClient(ctx context.Context, opts ...option.ClientOption) (*ConfigClient, error) {
+ conn, err := transport.DialGRPC(ctx, append(defaultConfigClientOptions(), opts...)...)
+ if err != nil {
+ return nil, err
+ }
+ c := &ConfigClient{
+ conn: conn,
+ CallOptions: defaultConfigCallOptions(),
+
+ configClient: loggingpb.NewConfigServiceV2Client(conn),
+ }
+ c.SetGoogleClientInfo()
+ return c, nil
+}
+
+// Connection returns the client's connection to the API service.
+func (c *ConfigClient) Connection() *grpc.ClientConn {
+ return c.conn
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *ConfigClient) Close() error {
+ return c.conn.Close()
+}
+
+// SetGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *ConfigClient) SetGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", version.Go()}, keyval...)
+ kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
+ c.xGoogHeader = []string{gax.XGoogHeader(kv...)}
+}
+
+// ConfigProjectPath returns the path for the project resource.
+func ConfigProjectPath(project string) string {
+ path, err := configProjectPathTemplate.Render(map[string]string{
+ "project": project,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// ConfigSinkPath returns the path for the sink resource.
+func ConfigSinkPath(project, sink string) string {
+ path, err := configSinkPathTemplate.Render(map[string]string{
+ "project": project,
+ "sink": sink,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// ListSinks lists sinks.
+func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest, opts ...gax.CallOption) *LogSinkIterator {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.ListSinks[0:len(c.CallOptions.ListSinks):len(c.CallOptions.ListSinks)], opts...)
+ it := &LogSinkIterator{}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogSink, string, error) {
+ var resp *loggingpb.ListSinksResponse
+ req.PageToken = pageToken
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.configClient.ListSinks(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+ return resp.Sinks, resp.NextPageToken, nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ return it
+}
+
+// GetSink gets a sink.
+func (c *ConfigClient) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.GetSink[0:len(c.CallOptions.GetSink):len(c.CallOptions.GetSink)], opts...)
+ var resp *loggingpb.LogSink
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.configClient.GetSink(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// CreateSink creates a sink that exports specified log entries to a destination. The
+// export of newly-ingested log entries begins immediately, unless the current
+// time is outside the sink's start and end times or the sink's
+// `writer_identity` is not permitted to write to the destination. A sink can
+// export log entries only from the resource owning the sink.
+func (c *ConfigClient) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.CreateSink[0:len(c.CallOptions.CreateSink):len(c.CallOptions.CreateSink)], opts...)
+ var resp *loggingpb.LogSink
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.configClient.CreateSink(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// UpdateSink updates a sink. If the named sink doesn't exist, then this method is
+// identical to
+// [sinks.create](/logging/docs/api/reference/rest/v2/projects.sinks/create).
+// If the named sink does exist, then this method replaces the following
+// fields in the existing sink with values from the new sink: `destination`,
+// `filter`, `output_version_format`, `start_time`, and `end_time`.
+// The updated filter might also have a new `writer_identity`; see the
+// `unique_writer_identity` field.
+func (c *ConfigClient) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.UpdateSink[0:len(c.CallOptions.UpdateSink):len(c.CallOptions.UpdateSink)], opts...)
+ var resp *loggingpb.LogSink
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.configClient.UpdateSink(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteSink deletes a sink. If the sink has a unique `writer_identity`, then that
+// service account is also deleted.
+func (c *ConfigClient) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest, opts ...gax.CallOption) error {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.DeleteSink[0:len(c.CallOptions.DeleteSink):len(c.CallOptions.DeleteSink)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.configClient.DeleteSink(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+// LogSinkIterator manages a stream of *loggingpb.LogSink.
+type LogSinkIterator struct {
+ items []*loggingpb.LogSink
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogSink, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *LogSinkIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *LogSinkIterator) Next() (*loggingpb.LogSink, error) {
+ var item *loggingpb.LogSink
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *LogSinkIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *LogSinkIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go
new file mode 100644
index 000000000..620aa6505
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go
@@ -0,0 +1,125 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging_test
+
+import (
+ "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+func ExampleNewConfigClient() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use client.
+ _ = c
+}
+
+func ExampleConfigClient_ListSinks() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.ListSinksRequest{
+ // TODO: Fill request struct fields.
+ }
+ it := c.ListSinks(ctx, req)
+ for {
+ resp, err := it.Next()
+ if err != nil {
+ // TODO: Handle error.
+ break
+ }
+ // TODO: Use resp.
+ _ = resp
+ }
+}
+
+func ExampleConfigClient_GetSink() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.GetSinkRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.GetSink(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleConfigClient_CreateSink() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.CreateSinkRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.CreateSink(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleConfigClient_UpdateSink() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.UpdateSinkRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.UpdateSink(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleConfigClient_DeleteSink() {
+ ctx := context.Background()
+ c, err := logging.NewConfigClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.DeleteSinkRequest{
+ // TODO: Fill request struct fields.
+ }
+ err = c.DeleteSink(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/doc.go b/vendor/cloud.google.com/go/logging/apiv2/doc.go
new file mode 100644
index 000000000..3963c8b7d
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/doc.go
@@ -0,0 +1,46 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+// Package logging is an experimental, auto-generated package for the
+// logging API.
+//
+// The Stackdriver Logging API lets you write log entries and manage your
+// logs, log sinks and logs-based metrics.
+//
+// Use the client at cloud.google.com/go/logging in preference to this.
+package logging // import "cloud.google.com/go/logging/apiv2"
+
+import (
+ "golang.org/x/net/context"
+ "google.golang.org/grpc/metadata"
+)
+
+func insertXGoog(ctx context.Context, val []string) context.Context {
+ md, _ := metadata.FromOutgoingContext(ctx)
+ md = md.Copy()
+ md["x-goog-api-client"] = val
+ return metadata.NewOutgoingContext(ctx, md)
+}
+
+func DefaultAuthScopes() []string {
+ return []string{
+ "https://www.googleapis.com/auth/cloud-platform",
+ "https://www.googleapis.com/auth/cloud-platform.read-only",
+ "https://www.googleapis.com/auth/logging.admin",
+ "https://www.googleapis.com/auth/logging.read",
+ "https://www.googleapis.com/auth/logging.write",
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/logging_client.go b/vendor/cloud.google.com/go/logging/apiv2/logging_client.go
new file mode 100644
index 000000000..603893b35
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/logging_client.go
@@ -0,0 +1,443 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging
+
+import (
+ "math"
+ "time"
+
+ "cloud.google.com/go/internal/version"
+ gax "github.com/googleapis/gax-go"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ "google.golang.org/api/transport"
+ monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+var (
+ loggingProjectPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
+ loggingLogPathTemplate = gax.MustCompilePathTemplate("projects/{project}/logs/{log}")
+)
+
+// CallOptions contains the retry settings for each method of Client.
+type CallOptions struct {
+ DeleteLog []gax.CallOption
+ WriteLogEntries []gax.CallOption
+ ListLogEntries []gax.CallOption
+ ListMonitoredResourceDescriptors []gax.CallOption
+ ListLogs []gax.CallOption
+}
+
+func defaultClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ option.WithEndpoint("logging.googleapis.com:443"),
+ option.WithScopes(DefaultAuthScopes()...),
+ }
+}
+
+func defaultCallOptions() *CallOptions {
+ retry := map[[2]string][]gax.CallOption{
+ {"default", "idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.DeadlineExceeded,
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ {"default", "non_idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ {"list", "idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.DeadlineExceeded,
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ }
+ return &CallOptions{
+ DeleteLog: retry[[2]string{"default", "idempotent"}],
+ WriteLogEntries: retry[[2]string{"default", "non_idempotent"}],
+ ListLogEntries: retry[[2]string{"list", "idempotent"}],
+ ListMonitoredResourceDescriptors: retry[[2]string{"default", "idempotent"}],
+ ListLogs: retry[[2]string{"default", "idempotent"}],
+ }
+}
+
+// Client is a client for interacting with Stackdriver Logging API.
+type Client struct {
+ // The connection to the service.
+ conn *grpc.ClientConn
+
+ // The gRPC API client.
+ client loggingpb.LoggingServiceV2Client
+
+ // The call options for this service.
+ CallOptions *CallOptions
+
+ // The metadata to be sent with each request.
+ xGoogHeader []string
+}
+
+// NewClient creates a new logging service v2 client.
+//
+// Service for ingesting and querying logs.
+func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
+ conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...)
+ if err != nil {
+ return nil, err
+ }
+ c := &Client{
+ conn: conn,
+ CallOptions: defaultCallOptions(),
+
+ client: loggingpb.NewLoggingServiceV2Client(conn),
+ }
+ c.SetGoogleClientInfo()
+ return c, nil
+}
+
+// Connection returns the client's connection to the API service.
+func (c *Client) Connection() *grpc.ClientConn {
+ return c.conn
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *Client) Close() error {
+ return c.conn.Close()
+}
+
+// SetGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *Client) SetGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", version.Go()}, keyval...)
+ kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
+ c.xGoogHeader = []string{gax.XGoogHeader(kv...)}
+}
+
+// LoggingProjectPath returns the path for the project resource.
+func LoggingProjectPath(project string) string {
+ path, err := loggingProjectPathTemplate.Render(map[string]string{
+ "project": project,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// LoggingLogPath returns the path for the log resource.
+func LoggingLogPath(project, log string) string {
+ path, err := loggingLogPathTemplate.Render(map[string]string{
+ "project": project,
+ "log": log,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// DeleteLog deletes all the log entries in a log.
+// The log reappears if it receives new entries.
+// Log entries written shortly before the delete operation might not be
+// deleted.
+func (c *Client) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest, opts ...gax.CallOption) error {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.DeleteLog[0:len(c.CallOptions.DeleteLog):len(c.CallOptions.DeleteLog)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.client.DeleteLog(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+// WriteLogEntries writes log entries to Stackdriver Logging.
+func (c *Client) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest, opts ...gax.CallOption) (*loggingpb.WriteLogEntriesResponse, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.WriteLogEntries[0:len(c.CallOptions.WriteLogEntries):len(c.CallOptions.WriteLogEntries)], opts...)
+ var resp *loggingpb.WriteLogEntriesResponse
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.client.WriteLogEntries(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListLogEntries lists log entries. Use this method to retrieve log entries from
+// Stackdriver Logging. For ways to export log entries, see
+// [Exporting Logs](/logging/docs/export).
+func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest, opts ...gax.CallOption) *LogEntryIterator {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.ListLogEntries[0:len(c.CallOptions.ListLogEntries):len(c.CallOptions.ListLogEntries)], opts...)
+ it := &LogEntryIterator{}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogEntry, string, error) {
+ var resp *loggingpb.ListLogEntriesResponse
+ req.PageToken = pageToken
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.client.ListLogEntries(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+ return resp.Entries, resp.NextPageToken, nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ return it
+}
+
+// ListMonitoredResourceDescriptors lists the descriptors for monitored resource types used by Stackdriver
+// Logging.
+func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...)
+ it := &MonitoredResourceDescriptorIterator{}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) {
+ var resp *loggingpb.ListMonitoredResourceDescriptorsResponse
+ req.PageToken = pageToken
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.client.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+ return resp.ResourceDescriptors, resp.NextPageToken, nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ return it
+}
+
+// ListLogs lists the logs in projects, organizations, folders, or billing accounts.
+// Only logs that have entries are listed.
+func (c *Client) ListLogs(ctx context.Context, req *loggingpb.ListLogsRequest, opts ...gax.CallOption) *StringIterator {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.ListLogs[0:len(c.CallOptions.ListLogs):len(c.CallOptions.ListLogs)], opts...)
+ it := &StringIterator{}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) {
+ var resp *loggingpb.ListLogsResponse
+ req.PageToken = pageToken
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.client.ListLogs(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+ return resp.LogNames, resp.NextPageToken, nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ return it
+}
+
+// LogEntryIterator manages a stream of *loggingpb.LogEntry.
+type LogEntryIterator struct {
+ items []*loggingpb.LogEntry
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogEntry, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *LogEntryIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *LogEntryIterator) Next() (*loggingpb.LogEntry, error) {
+ var item *loggingpb.LogEntry
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *LogEntryIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *LogEntryIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// MonitoredResourceDescriptorIterator manages a stream of *monitoredrespb.MonitoredResourceDescriptor.
+type MonitoredResourceDescriptorIterator struct {
+ items []*monitoredrespb.MonitoredResourceDescriptor
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*monitoredrespb.MonitoredResourceDescriptor, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *MonitoredResourceDescriptorIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *MonitoredResourceDescriptorIterator) Next() (*monitoredrespb.MonitoredResourceDescriptor, error) {
+ var item *monitoredrespb.MonitoredResourceDescriptor
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *MonitoredResourceDescriptorIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// StringIterator manages a stream of string.
+type StringIterator struct {
+ items []string
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []string, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *StringIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *StringIterator) Next() (string, error) {
+ var item string
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *StringIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *StringIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go
new file mode 100644
index 000000000..6dc537f5a
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go
@@ -0,0 +1,133 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging_test
+
+import (
+ "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+func ExampleNewClient() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use client.
+ _ = c
+}
+
+func ExampleClient_DeleteLog() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.DeleteLogRequest{
+ // TODO: Fill request struct fields.
+ }
+ err = c.DeleteLog(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_WriteLogEntries() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.WriteLogEntriesRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.WriteLogEntries(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleClient_ListLogEntries() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.ListLogEntriesRequest{
+ // TODO: Fill request struct fields.
+ }
+ it := c.ListLogEntries(ctx, req)
+ for {
+ resp, err := it.Next()
+ if err != nil {
+ // TODO: Handle error.
+ break
+ }
+ // TODO: Use resp.
+ _ = resp
+ }
+}
+
+func ExampleClient_ListMonitoredResourceDescriptors() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.ListMonitoredResourceDescriptorsRequest{
+ // TODO: Fill request struct fields.
+ }
+ it := c.ListMonitoredResourceDescriptors(ctx, req)
+ for {
+ resp, err := it.Next()
+ if err != nil {
+ // TODO: Handle error.
+ break
+ }
+ // TODO: Use resp.
+ _ = resp
+ }
+}
+
+func ExampleClient_ListLogs() {
+ ctx := context.Background()
+ c, err := logging.NewClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.ListLogsRequest{
+ // TODO: Fill request struct fields.
+ }
+ it := c.ListLogs(ctx, req)
+ for {
+ resp, err := it.Next()
+ if err != nil {
+ // TODO: Handle error.
+ break
+ }
+ // TODO: Use resp.
+ _ = resp
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go b/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go
new file mode 100644
index 000000000..ba2af9284
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go
@@ -0,0 +1,301 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging
+
+import (
+ "math"
+ "time"
+
+ "cloud.google.com/go/internal/version"
+ gax "github.com/googleapis/gax-go"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ "google.golang.org/api/transport"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+var (
+ metricsProjectPathTemplate = gax.MustCompilePathTemplate("projects/{project}")
+ metricsMetricPathTemplate = gax.MustCompilePathTemplate("projects/{project}/metrics/{metric}")
+)
+
+// MetricsCallOptions contains the retry settings for each method of MetricsClient.
+type MetricsCallOptions struct {
+ ListLogMetrics []gax.CallOption
+ GetLogMetric []gax.CallOption
+ CreateLogMetric []gax.CallOption
+ UpdateLogMetric []gax.CallOption
+ DeleteLogMetric []gax.CallOption
+}
+
+func defaultMetricsClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ option.WithEndpoint("logging.googleapis.com:443"),
+ option.WithScopes(DefaultAuthScopes()...),
+ }
+}
+
+func defaultMetricsCallOptions() *MetricsCallOptions {
+ retry := map[[2]string][]gax.CallOption{
+ {"default", "idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.DeadlineExceeded,
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ {"default", "non_idempotent"}: {
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }),
+ },
+ }
+ return &MetricsCallOptions{
+ ListLogMetrics: retry[[2]string{"default", "idempotent"}],
+ GetLogMetric: retry[[2]string{"default", "idempotent"}],
+ CreateLogMetric: retry[[2]string{"default", "non_idempotent"}],
+ UpdateLogMetric: retry[[2]string{"default", "non_idempotent"}],
+ DeleteLogMetric: retry[[2]string{"default", "idempotent"}],
+ }
+}
+
+// MetricsClient is a client for interacting with Stackdriver Logging API.
+type MetricsClient struct {
+ // The connection to the service.
+ conn *grpc.ClientConn
+
+ // The gRPC API client.
+ metricsClient loggingpb.MetricsServiceV2Client
+
+ // The call options for this service.
+ CallOptions *MetricsCallOptions
+
+ // The metadata to be sent with each request.
+ xGoogHeader []string
+}
+
+// NewMetricsClient creates a new metrics service v2 client.
+//
+// Service for configuring logs-based metrics.
+func NewMetricsClient(ctx context.Context, opts ...option.ClientOption) (*MetricsClient, error) {
+ conn, err := transport.DialGRPC(ctx, append(defaultMetricsClientOptions(), opts...)...)
+ if err != nil {
+ return nil, err
+ }
+ c := &MetricsClient{
+ conn: conn,
+ CallOptions: defaultMetricsCallOptions(),
+
+ metricsClient: loggingpb.NewMetricsServiceV2Client(conn),
+ }
+ c.SetGoogleClientInfo()
+ return c, nil
+}
+
+// Connection returns the client's connection to the API service.
+func (c *MetricsClient) Connection() *grpc.ClientConn {
+ return c.conn
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *MetricsClient) Close() error {
+ return c.conn.Close()
+}
+
+// SetGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *MetricsClient) SetGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", version.Go()}, keyval...)
+ kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version)
+ c.xGoogHeader = []string{gax.XGoogHeader(kv...)}
+}
+
+// MetricsProjectPath returns the path for the project resource.
+func MetricsProjectPath(project string) string {
+ path, err := metricsProjectPathTemplate.Render(map[string]string{
+ "project": project,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// MetricsMetricPath returns the path for the metric resource.
+func MetricsMetricPath(project, metric string) string {
+ path, err := metricsMetricPathTemplate.Render(map[string]string{
+ "project": project,
+ "metric": metric,
+ })
+ if err != nil {
+ panic(err)
+ }
+ return path
+}
+
+// ListLogMetrics lists logs-based metrics.
+func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest, opts ...gax.CallOption) *LogMetricIterator {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.ListLogMetrics[0:len(c.CallOptions.ListLogMetrics):len(c.CallOptions.ListLogMetrics)], opts...)
+ it := &LogMetricIterator{}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogMetric, string, error) {
+ var resp *loggingpb.ListLogMetricsResponse
+ req.PageToken = pageToken
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.metricsClient.ListLogMetrics(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+ return resp.Metrics, resp.NextPageToken, nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ return it
+}
+
+// GetLogMetric gets a logs-based metric.
+func (c *MetricsClient) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.GetLogMetric[0:len(c.CallOptions.GetLogMetric):len(c.CallOptions.GetLogMetric)], opts...)
+ var resp *loggingpb.LogMetric
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.metricsClient.GetLogMetric(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// CreateLogMetric creates a logs-based metric.
+func (c *MetricsClient) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.CreateLogMetric[0:len(c.CallOptions.CreateLogMetric):len(c.CallOptions.CreateLogMetric)], opts...)
+ var resp *loggingpb.LogMetric
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.metricsClient.CreateLogMetric(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// UpdateLogMetric creates or updates a logs-based metric.
+func (c *MetricsClient) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.UpdateLogMetric[0:len(c.CallOptions.UpdateLogMetric):len(c.CallOptions.UpdateLogMetric)], opts...)
+ var resp *loggingpb.LogMetric
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.metricsClient.UpdateLogMetric(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteLogMetric deletes a logs-based metric.
+func (c *MetricsClient) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest, opts ...gax.CallOption) error {
+ ctx = insertXGoog(ctx, c.xGoogHeader)
+ opts = append(c.CallOptions.DeleteLogMetric[0:len(c.CallOptions.DeleteLogMetric):len(c.CallOptions.DeleteLogMetric)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.metricsClient.DeleteLogMetric(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+// LogMetricIterator manages a stream of *loggingpb.LogMetric.
+type LogMetricIterator struct {
+ items []*loggingpb.LogMetric
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogMetric, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *LogMetricIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *LogMetricIterator) Next() (*loggingpb.LogMetric, error) {
+ var item *loggingpb.LogMetric
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *LogMetricIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *LogMetricIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go
new file mode 100644
index 000000000..c92412047
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go
@@ -0,0 +1,125 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging_test
+
+import (
+ "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+func ExampleNewMetricsClient() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use client.
+ _ = c
+}
+
+func ExampleMetricsClient_ListLogMetrics() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.ListLogMetricsRequest{
+ // TODO: Fill request struct fields.
+ }
+ it := c.ListLogMetrics(ctx, req)
+ for {
+ resp, err := it.Next()
+ if err != nil {
+ // TODO: Handle error.
+ break
+ }
+ // TODO: Use resp.
+ _ = resp
+ }
+}
+
+func ExampleMetricsClient_GetLogMetric() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.GetLogMetricRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.GetLogMetric(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleMetricsClient_CreateLogMetric() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.CreateLogMetricRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.CreateLogMetric(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleMetricsClient_UpdateLogMetric() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.UpdateLogMetricRequest{
+ // TODO: Fill request struct fields.
+ }
+ resp, err := c.UpdateLogMetric(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: Use resp.
+ _ = resp
+}
+
+func ExampleMetricsClient_DeleteLogMetric() {
+ ctx := context.Background()
+ c, err := logging.NewMetricsClient(ctx)
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+ req := &loggingpb.DeleteLogMetricRequest{
+ // TODO: Fill request struct fields.
+ }
+ err = c.DeleteLogMetric(ctx, req)
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/apiv2/mock_test.go b/vendor/cloud.google.com/go/logging/apiv2/mock_test.go
new file mode 100644
index 000000000..30083a2a5
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/apiv2/mock_test.go
@@ -0,0 +1,1248 @@
+// Copyright 2017, 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.
+
+// AUTO-GENERATED CODE. DO NOT EDIT.
+
+package logging
+
+import (
+ emptypb "github.com/golang/protobuf/ptypes/empty"
+ monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
+ loggingpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/ptypes"
+ "golang.org/x/net/context"
+ "google.golang.org/api/option"
+ status "google.golang.org/genproto/googleapis/rpc/status"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+)
+
+var _ = io.EOF
+var _ = ptypes.MarshalAny
+var _ status.Status
+
+type mockLoggingServer struct {
+ // Embed for forward compatibility.
+ // Tests will keep working if more methods are added
+ // in the future.
+ loggingpb.LoggingServiceV2Server
+
+ reqs []proto.Message
+
+ // If set, all calls return this error.
+ err error
+
+ // responses to return if err == nil
+ resps []proto.Message
+}
+
+func (s *mockLoggingServer) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest) (*emptypb.Empty, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*emptypb.Empty), nil
+}
+
+func (s *mockLoggingServer) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest) (*loggingpb.WriteLogEntriesResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.WriteLogEntriesResponse), nil
+}
+
+func (s *mockLoggingServer) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest) (*loggingpb.ListLogEntriesResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.ListLogEntriesResponse), nil
+}
+
+func (s *mockLoggingServer) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest) (*loggingpb.ListMonitoredResourceDescriptorsResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.ListMonitoredResourceDescriptorsResponse), nil
+}
+
+func (s *mockLoggingServer) ListLogs(ctx context.Context, req *loggingpb.ListLogsRequest) (*loggingpb.ListLogsResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.ListLogsResponse), nil
+}
+
+type mockConfigServer struct {
+ // Embed for forward compatibility.
+ // Tests will keep working if more methods are added
+ // in the future.
+ loggingpb.ConfigServiceV2Server
+
+ reqs []proto.Message
+
+ // If set, all calls return this error.
+ err error
+
+ // responses to return if err == nil
+ resps []proto.Message
+}
+
+func (s *mockConfigServer) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest) (*loggingpb.ListSinksResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.ListSinksResponse), nil
+}
+
+func (s *mockConfigServer) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest) (*loggingpb.LogSink, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogSink), nil
+}
+
+func (s *mockConfigServer) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest) (*loggingpb.LogSink, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogSink), nil
+}
+
+func (s *mockConfigServer) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest) (*loggingpb.LogSink, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogSink), nil
+}
+
+func (s *mockConfigServer) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest) (*emptypb.Empty, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*emptypb.Empty), nil
+}
+
+type mockMetricsServer struct {
+ // Embed for forward compatibility.
+ // Tests will keep working if more methods are added
+ // in the future.
+ loggingpb.MetricsServiceV2Server
+
+ reqs []proto.Message
+
+ // If set, all calls return this error.
+ err error
+
+ // responses to return if err == nil
+ resps []proto.Message
+}
+
+func (s *mockMetricsServer) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest) (*loggingpb.ListLogMetricsResponse, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.ListLogMetricsResponse), nil
+}
+
+func (s *mockMetricsServer) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest) (*loggingpb.LogMetric, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogMetric), nil
+}
+
+func (s *mockMetricsServer) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest) (*loggingpb.LogMetric, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogMetric), nil
+}
+
+func (s *mockMetricsServer) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest) (*loggingpb.LogMetric, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*loggingpb.LogMetric), nil
+}
+
+func (s *mockMetricsServer) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest) (*emptypb.Empty, error) {
+ md, _ := metadata.FromIncomingContext(ctx)
+ if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") {
+ return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg)
+ }
+ s.reqs = append(s.reqs, req)
+ if s.err != nil {
+ return nil, s.err
+ }
+ return s.resps[0].(*emptypb.Empty), nil
+}
+
+// clientOpt is the option tests should use to connect to the test server.
+// It is initialized by TestMain.
+var clientOpt option.ClientOption
+
+var (
+ mockLogging mockLoggingServer
+ mockConfig mockConfigServer
+ mockMetrics mockMetricsServer
+)
+
+func TestMain(m *testing.M) {
+ flag.Parse()
+
+ serv := grpc.NewServer()
+ loggingpb.RegisterLoggingServiceV2Server(serv, &mockLogging)
+ loggingpb.RegisterConfigServiceV2Server(serv, &mockConfig)
+ loggingpb.RegisterMetricsServiceV2Server(serv, &mockMetrics)
+
+ lis, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ log.Fatal(err)
+ }
+ go serv.Serve(lis)
+
+ conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure())
+ if err != nil {
+ log.Fatal(err)
+ }
+ clientOpt = option.WithGRPCConn(conn)
+
+ os.Exit(m.Run())
+}
+
+func TestLoggingServiceV2DeleteLog(t *testing.T) {
+ var expectedResponse *emptypb.Empty = &emptypb.Empty{}
+
+ mockLogging.err = nil
+ mockLogging.reqs = nil
+
+ mockLogging.resps = append(mockLogging.resps[:0], expectedResponse)
+
+ var formattedLogName string = LoggingLogPath("[PROJECT]", "[LOG]")
+ var request = &loggingpb.DeleteLogRequest{
+ LogName: formattedLogName,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteLog(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+}
+
+func TestLoggingServiceV2DeleteLogError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockLogging.err = grpc.Errorf(errCode, "test error")
+
+ var formattedLogName string = LoggingLogPath("[PROJECT]", "[LOG]")
+ var request = &loggingpb.DeleteLogRequest{
+ LogName: formattedLogName,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteLog(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+}
+func TestLoggingServiceV2WriteLogEntries(t *testing.T) {
+ var expectedResponse *loggingpb.WriteLogEntriesResponse = &loggingpb.WriteLogEntriesResponse{}
+
+ mockLogging.err = nil
+ mockLogging.reqs = nil
+
+ mockLogging.resps = append(mockLogging.resps[:0], expectedResponse)
+
+ var entries []*loggingpb.LogEntry = nil
+ var request = &loggingpb.WriteLogEntriesRequest{
+ Entries: entries,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.WriteLogEntries(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestLoggingServiceV2WriteLogEntriesError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockLogging.err = grpc.Errorf(errCode, "test error")
+
+ var entries []*loggingpb.LogEntry = nil
+ var request = &loggingpb.WriteLogEntriesRequest{
+ Entries: entries,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.WriteLogEntries(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestLoggingServiceV2ListLogEntries(t *testing.T) {
+ var nextPageToken string = ""
+ var entriesElement *loggingpb.LogEntry = &loggingpb.LogEntry{}
+ var entries = []*loggingpb.LogEntry{entriesElement}
+ var expectedResponse = &loggingpb.ListLogEntriesResponse{
+ NextPageToken: nextPageToken,
+ Entries: entries,
+ }
+
+ mockLogging.err = nil
+ mockLogging.reqs = nil
+
+ mockLogging.resps = append(mockLogging.resps[:0], expectedResponse)
+
+ var resourceNames []string = nil
+ var request = &loggingpb.ListLogEntriesRequest{
+ ResourceNames: resourceNames,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogEntries(context.Background(), request).Next()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ want := (interface{})(expectedResponse.Entries[0])
+ got := (interface{})(resp)
+ var ok bool
+
+ switch want := (want).(type) {
+ case proto.Message:
+ ok = proto.Equal(want, got.(proto.Message))
+ default:
+ ok = want == got
+ }
+ if !ok {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestLoggingServiceV2ListLogEntriesError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockLogging.err = grpc.Errorf(errCode, "test error")
+
+ var resourceNames []string = nil
+ var request = &loggingpb.ListLogEntriesRequest{
+ ResourceNames: resourceNames,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogEntries(context.Background(), request).Next()
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestLoggingServiceV2ListMonitoredResourceDescriptors(t *testing.T) {
+ var nextPageToken string = ""
+ var resourceDescriptorsElement *monitoredrespb.MonitoredResourceDescriptor = &monitoredrespb.MonitoredResourceDescriptor{}
+ var resourceDescriptors = []*monitoredrespb.MonitoredResourceDescriptor{resourceDescriptorsElement}
+ var expectedResponse = &loggingpb.ListMonitoredResourceDescriptorsResponse{
+ NextPageToken: nextPageToken,
+ ResourceDescriptors: resourceDescriptors,
+ }
+
+ mockLogging.err = nil
+ mockLogging.reqs = nil
+
+ mockLogging.resps = append(mockLogging.resps[:0], expectedResponse)
+
+ var request *loggingpb.ListMonitoredResourceDescriptorsRequest = &loggingpb.ListMonitoredResourceDescriptorsRequest{}
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ want := (interface{})(expectedResponse.ResourceDescriptors[0])
+ got := (interface{})(resp)
+ var ok bool
+
+ switch want := (want).(type) {
+ case proto.Message:
+ ok = proto.Equal(want, got.(proto.Message))
+ default:
+ ok = want == got
+ }
+ if !ok {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestLoggingServiceV2ListMonitoredResourceDescriptorsError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockLogging.err = grpc.Errorf(errCode, "test error")
+
+ var request *loggingpb.ListMonitoredResourceDescriptorsRequest = &loggingpb.ListMonitoredResourceDescriptorsRequest{}
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next()
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestLoggingServiceV2ListLogs(t *testing.T) {
+ var nextPageToken string = ""
+ var logNamesElement string = "logNamesElement-1079688374"
+ var logNames = []string{logNamesElement}
+ var expectedResponse = &loggingpb.ListLogsResponse{
+ NextPageToken: nextPageToken,
+ LogNames: logNames,
+ }
+
+ mockLogging.err = nil
+ mockLogging.reqs = nil
+
+ mockLogging.resps = append(mockLogging.resps[:0], expectedResponse)
+
+ var formattedParent string = LoggingProjectPath("[PROJECT]")
+ var request = &loggingpb.ListLogsRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogs(context.Background(), request).Next()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ want := (interface{})(expectedResponse.LogNames[0])
+ got := (interface{})(resp)
+ var ok bool
+
+ switch want := (want).(type) {
+ case proto.Message:
+ ok = proto.Equal(want, got.(proto.Message))
+ default:
+ ok = want == got
+ }
+ if !ok {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestLoggingServiceV2ListLogsError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockLogging.err = grpc.Errorf(errCode, "test error")
+
+ var formattedParent string = LoggingProjectPath("[PROJECT]")
+ var request = &loggingpb.ListLogsRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogs(context.Background(), request).Next()
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestConfigServiceV2ListSinks(t *testing.T) {
+ var nextPageToken string = ""
+ var sinksElement *loggingpb.LogSink = &loggingpb.LogSink{}
+ var sinks = []*loggingpb.LogSink{sinksElement}
+ var expectedResponse = &loggingpb.ListSinksResponse{
+ NextPageToken: nextPageToken,
+ Sinks: sinks,
+ }
+
+ mockConfig.err = nil
+ mockConfig.reqs = nil
+
+ mockConfig.resps = append(mockConfig.resps[:0], expectedResponse)
+
+ var formattedParent string = ConfigProjectPath("[PROJECT]")
+ var request = &loggingpb.ListSinksRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListSinks(context.Background(), request).Next()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ want := (interface{})(expectedResponse.Sinks[0])
+ got := (interface{})(resp)
+ var ok bool
+
+ switch want := (want).(type) {
+ case proto.Message:
+ ok = proto.Equal(want, got.(proto.Message))
+ default:
+ ok = want == got
+ }
+ if !ok {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestConfigServiceV2ListSinksError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockConfig.err = grpc.Errorf(errCode, "test error")
+
+ var formattedParent string = ConfigProjectPath("[PROJECT]")
+ var request = &loggingpb.ListSinksRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListSinks(context.Background(), request).Next()
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestConfigServiceV2GetSink(t *testing.T) {
+ var name string = "name3373707"
+ var destination string = "destination-1429847026"
+ var filter string = "filter-1274492040"
+ var writerIdentity string = "writerIdentity775638794"
+ var includeChildren bool = true
+ var expectedResponse = &loggingpb.LogSink{
+ Name: name,
+ Destination: destination,
+ Filter: filter,
+ WriterIdentity: writerIdentity,
+ IncludeChildren: includeChildren,
+ }
+
+ mockConfig.err = nil
+ mockConfig.reqs = nil
+
+ mockConfig.resps = append(mockConfig.resps[:0], expectedResponse)
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var request = &loggingpb.GetSinkRequest{
+ SinkName: formattedSinkName,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.GetSink(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestConfigServiceV2GetSinkError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockConfig.err = grpc.Errorf(errCode, "test error")
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var request = &loggingpb.GetSinkRequest{
+ SinkName: formattedSinkName,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.GetSink(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestConfigServiceV2CreateSink(t *testing.T) {
+ var name string = "name3373707"
+ var destination string = "destination-1429847026"
+ var filter string = "filter-1274492040"
+ var writerIdentity string = "writerIdentity775638794"
+ var includeChildren bool = true
+ var expectedResponse = &loggingpb.LogSink{
+ Name: name,
+ Destination: destination,
+ Filter: filter,
+ WriterIdentity: writerIdentity,
+ IncludeChildren: includeChildren,
+ }
+
+ mockConfig.err = nil
+ mockConfig.reqs = nil
+
+ mockConfig.resps = append(mockConfig.resps[:0], expectedResponse)
+
+ var formattedParent string = ConfigProjectPath("[PROJECT]")
+ var sink *loggingpb.LogSink = &loggingpb.LogSink{}
+ var request = &loggingpb.CreateSinkRequest{
+ Parent: formattedParent,
+ Sink: sink,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.CreateSink(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestConfigServiceV2CreateSinkError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockConfig.err = grpc.Errorf(errCode, "test error")
+
+ var formattedParent string = ConfigProjectPath("[PROJECT]")
+ var sink *loggingpb.LogSink = &loggingpb.LogSink{}
+ var request = &loggingpb.CreateSinkRequest{
+ Parent: formattedParent,
+ Sink: sink,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.CreateSink(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestConfigServiceV2UpdateSink(t *testing.T) {
+ var name string = "name3373707"
+ var destination string = "destination-1429847026"
+ var filter string = "filter-1274492040"
+ var writerIdentity string = "writerIdentity775638794"
+ var includeChildren bool = true
+ var expectedResponse = &loggingpb.LogSink{
+ Name: name,
+ Destination: destination,
+ Filter: filter,
+ WriterIdentity: writerIdentity,
+ IncludeChildren: includeChildren,
+ }
+
+ mockConfig.err = nil
+ mockConfig.reqs = nil
+
+ mockConfig.resps = append(mockConfig.resps[:0], expectedResponse)
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var sink *loggingpb.LogSink = &loggingpb.LogSink{}
+ var request = &loggingpb.UpdateSinkRequest{
+ SinkName: formattedSinkName,
+ Sink: sink,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.UpdateSink(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestConfigServiceV2UpdateSinkError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockConfig.err = grpc.Errorf(errCode, "test error")
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var sink *loggingpb.LogSink = &loggingpb.LogSink{}
+ var request = &loggingpb.UpdateSinkRequest{
+ SinkName: formattedSinkName,
+ Sink: sink,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.UpdateSink(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestConfigServiceV2DeleteSink(t *testing.T) {
+ var expectedResponse *emptypb.Empty = &emptypb.Empty{}
+
+ mockConfig.err = nil
+ mockConfig.reqs = nil
+
+ mockConfig.resps = append(mockConfig.resps[:0], expectedResponse)
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var request = &loggingpb.DeleteSinkRequest{
+ SinkName: formattedSinkName,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteSink(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+}
+
+func TestConfigServiceV2DeleteSinkError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockConfig.err = grpc.Errorf(errCode, "test error")
+
+ var formattedSinkName string = ConfigSinkPath("[PROJECT]", "[SINK]")
+ var request = &loggingpb.DeleteSinkRequest{
+ SinkName: formattedSinkName,
+ }
+
+ c, err := NewConfigClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteSink(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+}
+func TestMetricsServiceV2ListLogMetrics(t *testing.T) {
+ var nextPageToken string = ""
+ var metricsElement *loggingpb.LogMetric = &loggingpb.LogMetric{}
+ var metrics = []*loggingpb.LogMetric{metricsElement}
+ var expectedResponse = &loggingpb.ListLogMetricsResponse{
+ NextPageToken: nextPageToken,
+ Metrics: metrics,
+ }
+
+ mockMetrics.err = nil
+ mockMetrics.reqs = nil
+
+ mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse)
+
+ var formattedParent string = MetricsProjectPath("[PROJECT]")
+ var request = &loggingpb.ListLogMetricsRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogMetrics(context.Background(), request).Next()
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ want := (interface{})(expectedResponse.Metrics[0])
+ got := (interface{})(resp)
+ var ok bool
+
+ switch want := (want).(type) {
+ case proto.Message:
+ ok = proto.Equal(want, got.(proto.Message))
+ default:
+ ok = want == got
+ }
+ if !ok {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestMetricsServiceV2ListLogMetricsError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockMetrics.err = grpc.Errorf(errCode, "test error")
+
+ var formattedParent string = MetricsProjectPath("[PROJECT]")
+ var request = &loggingpb.ListLogMetricsRequest{
+ Parent: formattedParent,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.ListLogMetrics(context.Background(), request).Next()
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestMetricsServiceV2GetLogMetric(t *testing.T) {
+ var name string = "name3373707"
+ var description string = "description-1724546052"
+ var filter string = "filter-1274492040"
+ var expectedResponse = &loggingpb.LogMetric{
+ Name: name,
+ Description: description,
+ Filter: filter,
+ }
+
+ mockMetrics.err = nil
+ mockMetrics.reqs = nil
+
+ mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse)
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var request = &loggingpb.GetLogMetricRequest{
+ MetricName: formattedMetricName,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.GetLogMetric(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestMetricsServiceV2GetLogMetricError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockMetrics.err = grpc.Errorf(errCode, "test error")
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var request = &loggingpb.GetLogMetricRequest{
+ MetricName: formattedMetricName,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.GetLogMetric(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestMetricsServiceV2CreateLogMetric(t *testing.T) {
+ var name string = "name3373707"
+ var description string = "description-1724546052"
+ var filter string = "filter-1274492040"
+ var expectedResponse = &loggingpb.LogMetric{
+ Name: name,
+ Description: description,
+ Filter: filter,
+ }
+
+ mockMetrics.err = nil
+ mockMetrics.reqs = nil
+
+ mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse)
+
+ var formattedParent string = MetricsProjectPath("[PROJECT]")
+ var metric *loggingpb.LogMetric = &loggingpb.LogMetric{}
+ var request = &loggingpb.CreateLogMetricRequest{
+ Parent: formattedParent,
+ Metric: metric,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.CreateLogMetric(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestMetricsServiceV2CreateLogMetricError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockMetrics.err = grpc.Errorf(errCode, "test error")
+
+ var formattedParent string = MetricsProjectPath("[PROJECT]")
+ var metric *loggingpb.LogMetric = &loggingpb.LogMetric{}
+ var request = &loggingpb.CreateLogMetricRequest{
+ Parent: formattedParent,
+ Metric: metric,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.CreateLogMetric(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestMetricsServiceV2UpdateLogMetric(t *testing.T) {
+ var name string = "name3373707"
+ var description string = "description-1724546052"
+ var filter string = "filter-1274492040"
+ var expectedResponse = &loggingpb.LogMetric{
+ Name: name,
+ Description: description,
+ Filter: filter,
+ }
+
+ mockMetrics.err = nil
+ mockMetrics.reqs = nil
+
+ mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse)
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var metric *loggingpb.LogMetric = &loggingpb.LogMetric{}
+ var request = &loggingpb.UpdateLogMetricRequest{
+ MetricName: formattedMetricName,
+ Metric: metric,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.UpdateLogMetric(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+ if want, got := expectedResponse, resp; !proto.Equal(want, got) {
+ t.Errorf("wrong response %q, want %q)", got, want)
+ }
+}
+
+func TestMetricsServiceV2UpdateLogMetricError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockMetrics.err = grpc.Errorf(errCode, "test error")
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var metric *loggingpb.LogMetric = &loggingpb.LogMetric{}
+ var request = &loggingpb.UpdateLogMetricRequest{
+ MetricName: formattedMetricName,
+ Metric: metric,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := c.UpdateLogMetric(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+ _ = resp
+}
+func TestMetricsServiceV2DeleteLogMetric(t *testing.T) {
+ var expectedResponse *emptypb.Empty = &emptypb.Empty{}
+
+ mockMetrics.err = nil
+ mockMetrics.reqs = nil
+
+ mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse)
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var request = &loggingpb.DeleteLogMetricRequest{
+ MetricName: formattedMetricName,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteLogMetric(context.Background(), request)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) {
+ t.Errorf("wrong request %q, want %q", got, want)
+ }
+
+}
+
+func TestMetricsServiceV2DeleteLogMetricError(t *testing.T) {
+ errCode := codes.PermissionDenied
+ mockMetrics.err = grpc.Errorf(errCode, "test error")
+
+ var formattedMetricName string = MetricsMetricPath("[PROJECT]", "[METRIC]")
+ var request = &loggingpb.DeleteLogMetricRequest{
+ MetricName: formattedMetricName,
+ }
+
+ c, err := NewMetricsClient(context.Background(), clientOpt)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = c.DeleteLogMetric(context.Background(), request)
+
+ if c := grpc.Code(err); c != errCode {
+ t.Errorf("got error code %q, want %q", c, errCode)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/doc.go b/vendor/cloud.google.com/go/logging/doc.go
new file mode 100644
index 000000000..32ca717f4
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/doc.go
@@ -0,0 +1,90 @@
+// 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 logging contains a Stackdriver Logging client suitable for writing logs.
+For reading logs, and working with sinks, metrics and monitored resources,
+see package cloud.google.com/go/logging/logadmin.
+
+This client uses Logging API v2.
+See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.
+
+
+Note: This package is in beta. Some backwards-incompatible changes may occur.
+
+
+Creating a Client
+
+Use a Client to interact with the Stackdriver Logging API.
+
+ // Create a Client
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+
+Basic Usage
+
+For most use-cases, you'll want to add log entries to a buffer to be periodically
+flushed (automatically and asynchronously) to the Stackdriver Logging service.
+
+ // Initialize a logger
+ lg := client.Logger("my-log")
+
+ // Add entry to log buffer
+ lg.Log(logging.Entry{Payload: "something happened!"})
+
+
+Closing your Client
+
+You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service.
+
+ // Close the client when finished.
+ err = client.Close()
+ if err != nil {
+ // TODO: Handle error.
+ }
+
+
+Synchronous Logging
+
+For critical errors, you may want to send your log entries immediately.
+LogSync is slow and will block until the log entry has been sent, so it is
+not recommended for basic use.
+
+ lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"})
+
+
+The Standard Logger Interface
+
+You may want use a standard log.Logger in your program.
+
+ // stdlg implements log.Logger
+ stdlg := lg.StandardLogger(logging.Info)
+ stdlg.Println("some info")
+
+
+Log Levels
+
+An Entry may have one of a number of severity levels associated with it.
+
+ logging.Entry{
+ Payload: "something terrible happened!",
+ Severity: logging.Critical,
+ }
+
+*/
+package logging // import "cloud.google.com/go/logging"
diff --git a/vendor/cloud.google.com/go/logging/examples_test.go b/vendor/cloud.google.com/go/logging/examples_test.go
new file mode 100644
index 000000000..167458dad
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/examples_test.go
@@ -0,0 +1,125 @@
+// 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 logging_test
+
+import (
+ "fmt"
+ "os"
+
+ "cloud.google.com/go/logging"
+ "golang.org/x/net/context"
+)
+
+func ExampleNewClient() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // Use client to manage logs, metrics and sinks.
+ // Close the client when finished.
+ if err := client.Close(); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_Ping() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ if err := client.Ping(ctx); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleNewClient_errorFunc() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // Print all errors to stdout.
+ client.OnError = func(e error) {
+ fmt.Fprintf(os.Stdout, "logging: %v", e)
+ }
+ // Use client to manage logs, metrics and sinks.
+ // Close the client when finished.
+ if err := client.Close(); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_Logger() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("my-log")
+ _ = lg // TODO: use the Logger.
+}
+
+func ExampleLogger_LogSync() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("my-log")
+ err = lg.LogSync(ctx, logging.Entry{Payload: "red alert"})
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleLogger_Log() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("my-log")
+ lg.Log(logging.Entry{Payload: "something happened"})
+}
+
+func ExampleLogger_Flush() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("my-log")
+ lg.Log(logging.Entry{Payload: "something happened"})
+ lg.Flush()
+}
+
+func ExampleLogger_StandardLogger() {
+ ctx := context.Background()
+ client, err := logging.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ lg := client.Logger("my-log")
+ slg := lg.StandardLogger(logging.Info)
+ slg.Println("an informative message")
+}
+
+func ExampleParseSeverity() {
+ sev := logging.ParseSeverity("ALERT")
+ fmt.Println(sev)
+ // Output: Alert
+}
diff --git a/vendor/cloud.google.com/go/logging/internal/common.go b/vendor/cloud.google.com/go/logging/internal/common.go
new file mode 100644
index 000000000..38cfbb5fa
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/internal/common.go
@@ -0,0 +1,39 @@
+// 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 internal
+
+import (
+ "fmt"
+ "strings"
+)
+
+const (
+ ProdAddr = "logging.googleapis.com:443"
+ Version = "0.2.0"
+)
+
+func LogPath(parent, logID string) string {
+ logID = strings.Replace(logID, "/", "%2F", -1)
+ return fmt.Sprintf("%s/logs/%s", parent, logID)
+}
+
+func LogIDFromPath(parent, path string) string {
+ start := len(parent) + len("/logs/")
+ if len(path) < start {
+ return ""
+ }
+ logID := path[start:]
+ return strings.Replace(logID, "%2F", "/", -1)
+}
diff --git a/vendor/cloud.google.com/go/logging/internal/testing/equal.go b/vendor/cloud.google.com/go/logging/internal/testing/equal.go
new file mode 100644
index 000000000..c95d1991d
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/internal/testing/equal.go
@@ -0,0 +1,42 @@
+/*
+Copyright 2017 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 testing
+
+import (
+ "fmt"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// Compare two payloads, assuming they are both proto.Messages
+// or both strings.
+func PayloadEqual(a, b interface{}) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a == nil || b == nil {
+ return false
+ }
+ switch a := a.(type) {
+ case proto.Message:
+ return proto.Equal(a, b.(proto.Message))
+ case string:
+ return a == b.(string)
+ default:
+ panic(fmt.Sprintf("payloadEqual: unexpected type %T", a))
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/internal/testing/fake.go b/vendor/cloud.google.com/go/logging/internal/testing/fake.go
new file mode 100644
index 000000000..c76974da3
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/internal/testing/fake.go
@@ -0,0 +1,418 @@
+/*
+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 testing provides support for testing the logging client.
+package testing
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ emptypb "github.com/golang/protobuf/ptypes/empty"
+ tspb "github.com/golang/protobuf/ptypes/timestamp"
+
+ "cloud.google.com/go/internal/testutil"
+ context "golang.org/x/net/context"
+ lpb "google.golang.org/genproto/googleapis/api/label"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+type loggingHandler struct {
+ logpb.LoggingServiceV2Server
+
+ mu sync.Mutex
+ logs map[string][]*logpb.LogEntry // indexed by log name
+}
+
+type configHandler struct {
+ logpb.ConfigServiceV2Server
+
+ mu sync.Mutex
+ sinks map[string]*logpb.LogSink // indexed by (full) sink name
+}
+
+type metricHandler struct {
+ logpb.MetricsServiceV2Server
+
+ mu sync.Mutex
+ metrics map[string]*logpb.LogMetric // indexed by (full) metric name
+}
+
+// NewServer creates a new in-memory fake server implementing the logging service.
+// It returns the address of the server.
+func NewServer() (string, error) {
+ srv, err := testutil.NewServer()
+ if err != nil {
+ return "", err
+ }
+ logpb.RegisterLoggingServiceV2Server(srv.Gsrv, &loggingHandler{
+ logs: make(map[string][]*logpb.LogEntry),
+ })
+ logpb.RegisterConfigServiceV2Server(srv.Gsrv, &configHandler{
+ sinks: make(map[string]*logpb.LogSink),
+ })
+ logpb.RegisterMetricsServiceV2Server(srv.Gsrv, &metricHandler{
+ metrics: make(map[string]*logpb.LogMetric),
+ })
+ srv.Start()
+ return srv.Addr, nil
+}
+
+// DeleteLog deletes a log and all its log entries. The log will reappear if it
+// receives new entries.
+func (h *loggingHandler) DeleteLog(_ context.Context, req *logpb.DeleteLogRequest) (*emptypb.Empty, error) {
+ // TODO(jba): return NotFound if log isn't there?
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ delete(h.logs, req.LogName)
+ return &emptypb.Empty{}, nil
+}
+
+// The only project ID that WriteLogEntries will accept.
+// Important for testing Ping.
+const validProjectID = "PROJECT_ID"
+
+// WriteLogEntries writes log entries to Stackdriver Logging. All log entries in
+// Stackdriver Logging are written by this method.
+func (h *loggingHandler) WriteLogEntries(_ context.Context, req *logpb.WriteLogEntriesRequest) (*logpb.WriteLogEntriesResponse, error) {
+ if !strings.HasPrefix(req.LogName, "projects/"+validProjectID+"/") {
+ return nil, fmt.Errorf("bad project ID: %q", req.LogName)
+ }
+ // TODO(jba): support insertId?
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ for _, e := range req.Entries {
+ // Assign timestamp if missing.
+ if e.Timestamp == nil {
+ e.Timestamp = &tspb.Timestamp{Seconds: time.Now().Unix(), Nanos: 0}
+ }
+ // Fill from common fields in request.
+ if e.LogName == "" {
+ e.LogName = req.LogName
+ }
+ if e.Resource == nil {
+ // TODO(jba): use a global one if nil?
+ e.Resource = req.Resource
+ }
+ for k, v := range req.Labels {
+ if _, ok := e.Labels[k]; !ok {
+ e.Labels[k] = v
+ }
+ }
+
+ // Store by log name.
+ h.logs[e.LogName] = append(h.logs[e.LogName], e)
+ }
+ return &logpb.WriteLogEntriesResponse{}, nil
+}
+
+// ListLogEntries lists log entries. Use this method to retrieve log entries
+// from Stackdriver Logging.
+//
+// This fake implementation ignores project IDs. It does not support full filtering, only
+// expressions of the form "logName = NAME".
+func (h *loggingHandler) ListLogEntries(_ context.Context, req *logpb.ListLogEntriesRequest) (*logpb.ListLogEntriesResponse, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ entries, err := h.filterEntries(req.Filter)
+ if err != nil {
+ return nil, err
+ }
+ if err = sortEntries(entries, req.OrderBy); err != nil {
+ return nil, err
+ }
+
+ from, to, nextPageToken, err := getPage(int(req.PageSize), req.PageToken, len(entries))
+ if err != nil {
+ return nil, err
+ }
+ return &logpb.ListLogEntriesResponse{
+ Entries: entries[from:to],
+ NextPageToken: nextPageToken,
+ }, nil
+}
+
+// getPage converts an incoming page size and token from an RPC request into
+// slice bounds and the outgoing next-page token.
+//
+// getPage assumes that the complete, unpaginated list of items exists as a
+// single slice. In addition to the page size and token, getPage needs the
+// length of that slice.
+//
+// getPage's first two return values should be used to construct a sub-slice of
+// the complete, unpaginated slice. E.g. if the complete slice is s, then
+// s[from:to] is the desired page. Its third return value should be set as the
+// NextPageToken field of the RPC response.
+func getPage(pageSize int, pageToken string, length int) (from, to int, nextPageToken string, err error) {
+ from, to = 0, length
+ if pageToken != "" {
+ from, err = strconv.Atoi(pageToken)
+ if err != nil {
+ return 0, 0, "", invalidArgument("bad page token")
+ }
+ if from >= length {
+ return length, length, "", nil
+ }
+ }
+ if pageSize > 0 && from+pageSize < length {
+ to = from + pageSize
+ nextPageToken = strconv.Itoa(to)
+ }
+ return from, to, nextPageToken, nil
+}
+
+func (h *loggingHandler) filterEntries(filter string) ([]*logpb.LogEntry, error) {
+ logName, err := parseFilter(filter)
+ if err != nil {
+ return nil, err
+ }
+ if logName != "" {
+ return h.logs[logName], nil
+ }
+ var entries []*logpb.LogEntry
+ for _, es := range h.logs {
+ entries = append(entries, es...)
+ }
+ return entries, nil
+}
+
+var filterRegexp = regexp.MustCompile(`^logName\s*=\s*"?([-_/.%\w]+)"?$`)
+
+// returns the log name, or "" for the empty filter
+func parseFilter(filter string) (string, error) {
+ if filter == "" {
+ return "", nil
+ }
+ subs := filterRegexp.FindStringSubmatch(filter)
+ if subs == nil {
+ return "", invalidArgument("bad filter")
+ }
+ return subs[1], nil // cannot panic by construction of regexp
+}
+
+func sortEntries(entries []*logpb.LogEntry, orderBy string) error {
+ switch orderBy {
+ case "", "timestamp asc":
+ sort.Sort(byTimestamp(entries))
+ return nil
+
+ case "timestamp desc":
+ sort.Sort(sort.Reverse(byTimestamp(entries)))
+ return nil
+
+ default:
+ return invalidArgument("bad order_by")
+ }
+}
+
+type byTimestamp []*logpb.LogEntry
+
+func (s byTimestamp) Len() int { return len(s) }
+func (s byTimestamp) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byTimestamp) Less(i, j int) bool {
+ c := compareTimestamps(s[i].Timestamp, s[j].Timestamp)
+ switch {
+ case c < 0:
+ return true
+ case c > 0:
+ return false
+ default:
+ return s[i].InsertId < s[j].InsertId
+ }
+}
+
+func compareTimestamps(ts1, ts2 *tspb.Timestamp) int64 {
+ if ts1.Seconds != ts2.Seconds {
+ return ts1.Seconds - ts2.Seconds
+ }
+ return int64(ts1.Nanos - ts2.Nanos)
+}
+
+// Lists monitored resource descriptors that are used by Stackdriver Logging.
+func (h *loggingHandler) ListMonitoredResourceDescriptors(context.Context, *logpb.ListMonitoredResourceDescriptorsRequest) (*logpb.ListMonitoredResourceDescriptorsResponse, error) {
+ return &logpb.ListMonitoredResourceDescriptorsResponse{
+ ResourceDescriptors: []*mrpb.MonitoredResourceDescriptor{
+ {
+ Type: "global",
+ DisplayName: "Global",
+ Description: "... a log is not associated with any specific resource.",
+ Labels: []*lpb.LabelDescriptor{
+ {Key: "project_id", Description: "The identifier of the GCP project..."},
+ },
+ },
+ },
+ }, nil
+}
+
+// Lists logs.
+func (h *loggingHandler) ListLogs(_ context.Context, req *logpb.ListLogsRequest) (*logpb.ListLogsResponse, error) {
+ // Return fixed, fake response.
+ logNames := []string{"a", "b", "c"}
+ from, to, npt, err := getPage(int(req.PageSize), req.PageToken, len(logNames))
+ if err != nil {
+ return nil, err
+ }
+ return &logpb.ListLogsResponse{
+ LogNames: logNames[from:to],
+ NextPageToken: npt,
+ }, nil
+}
+
+// Gets a sink.
+func (h *configHandler) GetSink(_ context.Context, req *logpb.GetSinkRequest) (*logpb.LogSink, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ if s, ok := h.sinks[req.SinkName]; ok {
+ return s, nil
+ }
+ // TODO(jba): use error codes
+ return nil, fmt.Errorf("sink %q not found", req.SinkName)
+}
+
+// Creates a sink.
+func (h *configHandler) CreateSink(_ context.Context, req *logpb.CreateSinkRequest) (*logpb.LogSink, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ fullName := fmt.Sprintf("%s/sinks/%s", req.Parent, req.Sink.Name)
+ if _, ok := h.sinks[fullName]; ok {
+ return nil, fmt.Errorf("sink with name %q already exists", fullName)
+ }
+ h.sinks[fullName] = req.Sink
+ return req.Sink, nil
+}
+
+// Creates or updates a sink.
+func (h *configHandler) UpdateSink(_ context.Context, req *logpb.UpdateSinkRequest) (*logpb.LogSink, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ // Update of a non-existent sink will create it.
+ h.sinks[req.SinkName] = req.Sink
+ return req.Sink, nil
+}
+
+// Deletes a sink.
+func (h *configHandler) DeleteSink(_ context.Context, req *logpb.DeleteSinkRequest) (*emptypb.Empty, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ delete(h.sinks, req.SinkName)
+ return &emptypb.Empty{}, nil
+}
+
+// Lists sinks. This fake implementation ignores the Parent field of
+// ListSinksRequest. All sinks are listed, regardless of their project.
+func (h *configHandler) ListSinks(_ context.Context, req *logpb.ListSinksRequest) (*logpb.ListSinksResponse, error) {
+ h.mu.Lock()
+ var sinks []*logpb.LogSink
+ for _, s := range h.sinks {
+ sinks = append(sinks, s)
+ }
+ h.mu.Unlock() // safe because no *logpb.LogSink is ever modified
+ // Since map iteration varies, sort the sinks.
+ sort.Sort(sinksByName(sinks))
+ from, to, nextPageToken, err := getPage(int(req.PageSize), req.PageToken, len(sinks))
+ if err != nil {
+ return nil, err
+ }
+ return &logpb.ListSinksResponse{
+ Sinks: sinks[from:to],
+ NextPageToken: nextPageToken,
+ }, nil
+}
+
+type sinksByName []*logpb.LogSink
+
+func (s sinksByName) Len() int { return len(s) }
+func (s sinksByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s sinksByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
+
+// Gets a metric.
+func (h *metricHandler) GetLogMetric(_ context.Context, req *logpb.GetLogMetricRequest) (*logpb.LogMetric, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ if s, ok := h.metrics[req.MetricName]; ok {
+ return s, nil
+ }
+ // TODO(jba): use error codes
+ return nil, fmt.Errorf("metric %q not found", req.MetricName)
+}
+
+// Creates a metric.
+func (h *metricHandler) CreateLogMetric(_ context.Context, req *logpb.CreateLogMetricRequest) (*logpb.LogMetric, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ fullName := fmt.Sprintf("%s/metrics/%s", req.Parent, req.Metric.Name)
+ if _, ok := h.metrics[fullName]; ok {
+ return nil, fmt.Errorf("metric with name %q already exists", fullName)
+ }
+ h.metrics[fullName] = req.Metric
+ return req.Metric, nil
+}
+
+// Creates or updates a metric.
+func (h *metricHandler) UpdateLogMetric(_ context.Context, req *logpb.UpdateLogMetricRequest) (*logpb.LogMetric, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ // Update of a non-existent metric will create it.
+ h.metrics[req.MetricName] = req.Metric
+ return req.Metric, nil
+}
+
+// Deletes a metric.
+func (h *metricHandler) DeleteLogMetric(_ context.Context, req *logpb.DeleteLogMetricRequest) (*emptypb.Empty, error) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ delete(h.metrics, req.MetricName)
+ return &emptypb.Empty{}, nil
+}
+
+// Lists metrics. This fake implementation ignores the Parent field of
+// ListMetricsRequest. All metrics are listed, regardless of their project.
+func (h *metricHandler) ListLogMetrics(_ context.Context, req *logpb.ListLogMetricsRequest) (*logpb.ListLogMetricsResponse, error) {
+ h.mu.Lock()
+ var metrics []*logpb.LogMetric
+ for _, s := range h.metrics {
+ metrics = append(metrics, s)
+ }
+ h.mu.Unlock() // safe because no *logpb.LogMetric is ever modified
+ // Since map iteration varies, sort the metrics.
+ sort.Sort(metricsByName(metrics))
+ from, to, nextPageToken, err := getPage(int(req.PageSize), req.PageToken, len(metrics))
+ if err != nil {
+ return nil, err
+ }
+ return &logpb.ListLogMetricsResponse{
+ Metrics: metrics[from:to],
+ NextPageToken: nextPageToken,
+ }, nil
+}
+
+type metricsByName []*logpb.LogMetric
+
+func (s metricsByName) Len() int { return len(s) }
+func (s metricsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s metricsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
+
+func invalidArgument(msg string) error {
+ // TODO(jba): status codes
+ return errors.New(msg)
+}
diff --git a/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go b/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go
new file mode 100644
index 000000000..cd6e5c2f5
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go
@@ -0,0 +1,122 @@
+/*
+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.
+*/
+
+// This file contains only basic checks. The fake is effectively tested by the
+// logging client unit tests.
+
+package testing
+
+import (
+ "testing"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ tspb "github.com/golang/protobuf/ptypes/timestamp"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+ grpc "google.golang.org/grpc"
+)
+
+func TestNewServer(t *testing.T) {
+ // Confirm that we can create and use a working gRPC server.
+ addr, err := NewServer()
+ if err != nil {
+ t.Fatal(err)
+ }
+ conn, err := grpc.Dial(addr, grpc.WithInsecure())
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Avoid "connection is closing; please retry" message from gRPC.
+ time.Sleep(300 * time.Millisecond)
+ conn.Close()
+}
+
+func TestParseFilter(t *testing.T) {
+ for _, test := range []struct {
+ filter string
+ want string
+ wantErr bool
+ }{
+ {"", "", false},
+ {"logName = syslog", "syslog", false},
+ {"logname = syslog", "", true},
+ {"logName = 'syslog'", "", true},
+ {"logName == syslog", "", true},
+ } {
+ got, err := parseFilter(test.filter)
+ if err != nil {
+ if !test.wantErr {
+ t.Errorf("%q: got %v, want no error", test.filter, err)
+ }
+ continue
+ }
+ if test.wantErr {
+ t.Errorf("%q: got no error, want one", test.filter)
+ continue
+ }
+ if got != test.want {
+ t.Errorf("%q: got %q, want %q", test.filter, got, test.want)
+ }
+ }
+}
+
+func TestSortEntries(t *testing.T) {
+ entries := []*logpb.LogEntry{
+ /* 0 */ {Timestamp: &tspb.Timestamp{Seconds: 30}},
+ /* 1 */ {Timestamp: &tspb.Timestamp{Seconds: 10}},
+ /* 2 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "b"},
+ /* 3 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "a"},
+ /* 4 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "c"},
+ }
+ for _, test := range []struct {
+ orderBy string
+ want []int // slice of index into entries; nil == error
+ }{
+ {"", []int{1, 3, 2, 4, 0}},
+ {"timestamp asc", []int{1, 3, 2, 4, 0}},
+ {"timestamp desc", []int{0, 4, 2, 3, 1}},
+ {"something else", nil},
+ } {
+ got := make([]*logpb.LogEntry, len(entries))
+ copy(got, entries)
+ err := sortEntries(got, test.orderBy)
+ if err != nil {
+ if test.want != nil {
+ t.Errorf("%q: got %v, want nil error", test.orderBy, err)
+ }
+ continue
+ }
+ want := make([]*logpb.LogEntry, len(entries))
+ for i, j := range test.want {
+ want[i] = entries[j]
+ }
+ if !logEntriesEqual(got, want) {
+ t.Errorf("%q: got %v, want %v", test.orderBy, got, want)
+ }
+ }
+}
+
+func logEntriesEqual(a, b []*logpb.LogEntry) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, aa := range a {
+ if !proto.Equal(aa, b[i]) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go
new file mode 100644
index 000000000..39e6f5758
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go
@@ -0,0 +1,66 @@
+// 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 logadmin_test
+
+import (
+ "fmt"
+ "time"
+
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+func ExampleClient_Entries() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Entries(ctx, logadmin.Filter(`logName = "projects/my-project/logs/my-log"`))
+ _ = it // TODO: iterate using Next or iterator.Pager.
+}
+
+func ExampleFilter_timestamp() {
+ // This example demonstrates how to list the last 24 hours of log entries.
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ oneDayAgo := time.Now().Add(-24 * time.Hour)
+ t := oneDayAgo.Format(time.RFC3339) // Logging API wants timestamps in RFC 3339 format.
+ it := client.Entries(ctx, logadmin.Filter(fmt.Sprintf(`timestamp > "%s"`, t)))
+ _ = it // TODO: iterate using Next or iterator.Pager.
+}
+
+func ExampleEntryIterator_Next() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Entries(ctx)
+ for {
+ entry, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(entry)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go
new file mode 100644
index 000000000..2e876e9f8
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go
@@ -0,0 +1,52 @@
+// 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 logadmin_test
+
+import (
+ "fmt"
+
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+func ExampleClient_Metrics() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Metrics(ctx)
+ _ = it // TODO: iterate using Next or iterator.Pager.
+}
+
+func ExampleMetricIterator_Next() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Metrics(ctx)
+ for {
+ metric, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(metric)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go
new file mode 100644
index 000000000..036eeeb99
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go
@@ -0,0 +1,92 @@
+// 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 logadmin_test
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+
+ "cloud.google.com/go/logging"
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+var (
+ client *logadmin.Client
+ projectID = flag.String("project-id", "", "ID of the project to use")
+)
+
+func ExampleClient_Entries_pagination() {
+ // This example demonstrates how to iterate through items a page at a time
+ // even if each successive page is fetched by a different process. It is a
+ // complete web server that displays pages of log entries. To run it as a
+ // standalone program, rename both the package and this function to "main".
+ ctx := context.Background()
+ flag.Parse()
+ if *projectID == "" {
+ log.Fatal("-project-id missing")
+ }
+ var err error
+ client, err = logadmin.NewClient(ctx, *projectID)
+ if err != nil {
+ log.Fatalf("creating logging client: %v", err)
+ }
+
+ http.HandleFunc("/entries", handleEntries)
+ log.Print("listening on 8080")
+ log.Fatal(http.ListenAndServe(":8080", nil))
+}
+
+var pageTemplate = template.Must(template.New("").Parse(`
+<table>
+ {{range .Entries}}
+ <tr><td>{{.}}</td></tr>
+ {{end}}
+</table>
+{{if .Next}}
+ <a href="/entries?pageToken={{.Next}}">Next Page</a>
+{{end}}
+`))
+
+func handleEntries(w http.ResponseWriter, r *http.Request) {
+ ctx := context.Background()
+ filter := fmt.Sprintf(`logName = "projects/%s/logs/testlog"`, *projectID)
+ it := client.Entries(ctx, logadmin.Filter(filter))
+ var entries []*logging.Entry
+ nextTok, err := iterator.NewPager(it, 5, r.URL.Query().Get("pageToken")).NextPage(&entries)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("problem getting the next page: %v", err), http.StatusInternalServerError)
+ return
+ }
+ data := struct {
+ Entries []*logging.Entry
+ Next string
+ }{
+ entries,
+ nextTok,
+ }
+ var buf bytes.Buffer
+ if err := pageTemplate.Execute(&buf, data); err != nil {
+ http.Error(w, fmt.Sprintf("problem executing page template: %v", err), http.StatusInternalServerError)
+ }
+ if _, err := buf.WriteTo(w); err != nil {
+ log.Printf("writing response: %v", err)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go
new file mode 100644
index 000000000..fe67e2333
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go
@@ -0,0 +1,52 @@
+// 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 logadmin_test
+
+import (
+ "fmt"
+
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+func ExampleClient_ResourceDescriptors() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.ResourceDescriptors(ctx)
+ _ = it // TODO: iterate using Next or iterator.Pager.
+}
+
+func ExampleResourceDescriptorIterator_Next() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.ResourceDescriptors(ctx)
+ for {
+ rdesc, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(rdesc)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go
new file mode 100644
index 000000000..918fd9ffb
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go
@@ -0,0 +1,52 @@
+// 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 logadmin_test
+
+import (
+ "fmt"
+
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+func ExampleClient_Sinks() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Sinks(ctx)
+ _ = it // TODO: iterate using Next or iterator.Pager.
+}
+
+func ExampleSinkIterator_Next() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ it := client.Sinks(ctx)
+ for {
+ sink, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(sink)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/examples_test.go b/vendor/cloud.google.com/go/logging/logadmin/examples_test.go
new file mode 100644
index 000000000..0926dd5fd
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/examples_test.go
@@ -0,0 +1,161 @@
+// 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 logadmin_test
+
+import (
+ "fmt"
+
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+)
+
+func ExampleNewClient() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // Use client to manage logs, metrics and sinks.
+ // Close the client when finished.
+ if err := client.Close(); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_DeleteLog() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ err = client.DeleteLog(ctx, "my-log")
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_CreateMetric() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ err = client.CreateMetric(ctx, &logadmin.Metric{
+ ID: "severe-errors",
+ Description: "entries at ERROR or higher severities",
+ Filter: "severity >= ERROR",
+ })
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_DeleteMetric() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ if err := client.DeleteMetric(ctx, "severe-errors"); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_Metric() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ m, err := client.Metric(ctx, "severe-errors")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(m)
+}
+
+func ExampleClient_UpdateMetric() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ err = client.UpdateMetric(ctx, &logadmin.Metric{
+ ID: "severe-errors",
+ Description: "entries at high severities",
+ Filter: "severity > ERROR",
+ })
+ if err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_CreateSink() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ sink, err := client.CreateSink(ctx, &logadmin.Sink{
+ ID: "severe-errors-to-gcs",
+ Destination: "storage.googleapis.com/my-bucket",
+ Filter: "severity >= ERROR",
+ })
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(sink)
+}
+
+func ExampleClient_DeleteSink() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ if err := client.DeleteSink(ctx, "severe-errors-to-gcs"); err != nil {
+ // TODO: Handle error.
+ }
+}
+
+func ExampleClient_Sink() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ s, err := client.Sink(ctx, "severe-errors-to-gcs")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(s)
+}
+
+func ExampleClient_UpdateSink() {
+ ctx := context.Background()
+ client, err := logadmin.NewClient(ctx, "my-project")
+ if err != nil {
+ // TODO: Handle error.
+ }
+ sink, err := client.UpdateSink(ctx, &logadmin.Sink{
+ ID: "severe-errors-to-gcs",
+ Destination: "storage.googleapis.com/my-other-bucket",
+ Filter: "severity >= ERROR",
+ })
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(sink)
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/logadmin.go b/vendor/cloud.google.com/go/logging/logadmin/logadmin.go
new file mode 100644
index 000000000..9ea728c8b
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/logadmin.go
@@ -0,0 +1,402 @@
+// 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.
+
+// These features are missing now, but will likely be added:
+// - There is no way to specify CallOptions.
+
+// Package logadmin contains a Stackdriver Logging client that can be used
+// for reading logs and working with sinks, metrics and monitored resources.
+// For a client that can write logs, see package cloud.google.com/go/logging.
+//
+// The client uses Logging API v2.
+// See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API.
+//
+// Note: This package is in beta. Some backwards-incompatible changes may occur.
+package logadmin // import "cloud.google.com/go/logging/logadmin"
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "cloud.google.com/go/internal/version"
+ "cloud.google.com/go/logging"
+ vkit "cloud.google.com/go/logging/apiv2"
+ "cloud.google.com/go/logging/internal"
+ "github.com/golang/protobuf/ptypes"
+ gax "github.com/googleapis/gax-go"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ logtypepb "google.golang.org/genproto/googleapis/logging/type"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+ "google.golang.org/grpc/codes"
+ // Import the following so EntryIterator can unmarshal log protos.
+ _ "google.golang.org/genproto/googleapis/cloud/audit"
+)
+
+// Client is a Logging client. A Client is associated with a single Cloud project.
+type Client struct {
+ lClient *vkit.Client // logging client
+ sClient *vkit.ConfigClient // sink client
+ mClient *vkit.MetricsClient // metric client
+ projectID string
+ closed bool
+}
+
+// NewClient returns a new logging client associated with the provided project ID.
+//
+// By default NewClient uses AdminScope. To use a different scope, call
+// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes).
+func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
+ // Check for '/' in project ID to reserve the ability to support various owning resources,
+ // in the form "{Collection}/{Name}", for instance "organizations/my-org".
+ if strings.ContainsRune(projectID, '/') {
+ return nil, errors.New("logging: project ID contains '/'")
+ }
+ opts = append([]option.ClientOption{
+ option.WithEndpoint(internal.ProdAddr),
+ option.WithScopes(logging.AdminScope),
+ }, opts...)
+ lc, err := vkit.NewClient(ctx, opts...)
+ if err != nil {
+ return nil, err
+ }
+ // TODO(jba): pass along any client options that should be provided to all clients.
+ sc, err := vkit.NewConfigClient(ctx, option.WithGRPCConn(lc.Connection()))
+ if err != nil {
+ return nil, err
+ }
+ mc, err := vkit.NewMetricsClient(ctx, option.WithGRPCConn(lc.Connection()))
+ if err != nil {
+ return nil, err
+ }
+ // Retry some non-idempotent methods on INTERNAL, because it happens sometimes
+ // and in all observed cases the operation did not complete.
+ retryerOnInternal := func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Internal,
+ }, gax.Backoff{
+ Initial: 100 * time.Millisecond,
+ Max: 1000 * time.Millisecond,
+ Multiplier: 1.2,
+ })
+ }
+ mc.CallOptions.CreateLogMetric = []gax.CallOption{gax.WithRetry(retryerOnInternal)}
+ mc.CallOptions.UpdateLogMetric = []gax.CallOption{gax.WithRetry(retryerOnInternal)}
+
+ lc.SetGoogleClientInfo("gccl", version.Repo)
+ sc.SetGoogleClientInfo("gccl", version.Repo)
+ mc.SetGoogleClientInfo("gccl", version.Repo)
+ client := &Client{
+ lClient: lc,
+ sClient: sc,
+ mClient: mc,
+ projectID: projectID,
+ }
+ return client, nil
+}
+
+// parent returns the string used in many RPCs to denote the parent resource of the log.
+func (c *Client) parent() string {
+ return "projects/" + c.projectID
+}
+
+// Close closes the client.
+func (c *Client) Close() error {
+ if c.closed {
+ return nil
+ }
+ // Return only the first error. Since all clients share an underlying connection,
+ // Closes after the first always report a "connection is closing" error.
+ err := c.lClient.Close()
+ _ = c.sClient.Close()
+ _ = c.mClient.Close()
+ c.closed = true
+ return err
+}
+
+// DeleteLog deletes a log and all its log entries. The log will reappear if it receives new entries.
+// logID identifies the log within the project. An example log ID is "syslog". Requires AdminScope.
+func (c *Client) DeleteLog(ctx context.Context, logID string) error {
+ return c.lClient.DeleteLog(ctx, &logpb.DeleteLogRequest{
+ LogName: internal.LogPath(c.parent(), logID),
+ })
+}
+
+func toHTTPRequest(p *logtypepb.HttpRequest) (*logging.HTTPRequest, error) {
+ if p == nil {
+ return nil, nil
+ }
+ u, err := url.Parse(p.RequestUrl)
+ if err != nil {
+ return nil, err
+ }
+ var dur time.Duration
+ if p.Latency != nil {
+ dur, err = ptypes.Duration(p.Latency)
+ if err != nil {
+ return nil, err
+ }
+ }
+ hr := &http.Request{
+ Method: p.RequestMethod,
+ URL: u,
+ Header: map[string][]string{},
+ }
+ if p.UserAgent != "" {
+ hr.Header.Set("User-Agent", p.UserAgent)
+ }
+ if p.Referer != "" {
+ hr.Header.Set("Referer", p.Referer)
+ }
+ return &logging.HTTPRequest{
+ Request: hr,
+ RequestSize: p.RequestSize,
+ Status: int(p.Status),
+ ResponseSize: p.ResponseSize,
+ Latency: dur,
+ RemoteIP: p.RemoteIp,
+ CacheHit: p.CacheHit,
+ CacheValidatedWithOriginServer: p.CacheValidatedWithOriginServer,
+ }, nil
+}
+
+// An EntriesOption is an option for listing log entries.
+type EntriesOption interface {
+ set(*logpb.ListLogEntriesRequest)
+}
+
+// ProjectIDs sets the project IDs or project numbers from which to retrieve
+// log entries. Examples of a project ID: "my-project-1A", "1234567890".
+func ProjectIDs(pids []string) EntriesOption { return projectIDs(pids) }
+
+type projectIDs []string
+
+func (p projectIDs) set(r *logpb.ListLogEntriesRequest) {
+ r.ResourceNames = make([]string, len(p))
+ for i, v := range p {
+ r.ResourceNames[i] = fmt.Sprintf("projects/%s", v)
+ }
+}
+
+// Filter sets an advanced logs filter for listing log entries (see
+// https://cloud.google.com/logging/docs/view/advanced_filters). The filter is
+// compared against all log entries in the projects specified by ProjectIDs.
+// Only entries that match the filter are retrieved. An empty filter (the
+// default) matches all log entries.
+//
+// In the filter string, log names must be written in their full form, as
+// "projects/PROJECT-ID/logs/LOG-ID". Forward slashes in LOG-ID must be
+// replaced by %2F before calling Filter.
+//
+// Timestamps in the filter string must be written in RFC 3339 format. See the
+// timestamp example.
+func Filter(f string) EntriesOption { return filter(f) }
+
+type filter string
+
+func (f filter) set(r *logpb.ListLogEntriesRequest) { r.Filter = string(f) }
+
+// NewestFirst causes log entries to be listed from most recent (newest) to
+// least recent (oldest). By default, they are listed from oldest to newest.
+func NewestFirst() EntriesOption { return newestFirst{} }
+
+type newestFirst struct{}
+
+func (newestFirst) set(r *logpb.ListLogEntriesRequest) { r.OrderBy = "timestamp desc" }
+
+// Entries returns an EntryIterator for iterating over log entries. By default,
+// the log entries will be restricted to those from the project passed to
+// NewClient. This may be overridden by passing a ProjectIDs option. Requires ReadScope or AdminScope.
+func (c *Client) Entries(ctx context.Context, opts ...EntriesOption) *EntryIterator {
+ it := &EntryIterator{
+ it: c.lClient.ListLogEntries(ctx, listLogEntriesRequest(c.projectID, opts)),
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ return it
+}
+
+func listLogEntriesRequest(projectID string, opts []EntriesOption) *logpb.ListLogEntriesRequest {
+ req := &logpb.ListLogEntriesRequest{
+ ResourceNames: []string{"projects/" + projectID},
+ }
+ for _, opt := range opts {
+ opt.set(req)
+ }
+ return req
+}
+
+// An EntryIterator iterates over log entries.
+type EntryIterator struct {
+ it *vkit.LogEntryIterator
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []*logging.Entry
+}
+
+// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details.
+func (it *EntryIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is iterator.Done
+// (https://godoc.org/google.golang.org/api/iterator) if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *EntryIterator) Next() (*logging.Entry, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *EntryIterator) fetch(pageSize int, pageToken string) (string, error) {
+ return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
+ item, err := it.it.Next()
+ if err != nil {
+ return err
+ }
+ e, err := fromLogEntry(item)
+ if err != nil {
+ return err
+ }
+ it.items = append(it.items, e)
+ return nil
+ })
+}
+
+func trunc32(i int) int32 {
+ if i > math.MaxInt32 {
+ i = math.MaxInt32
+ }
+ return int32(i)
+}
+
+var slashUnescaper = strings.NewReplacer("%2F", "/", "%2f", "/")
+
+func fromLogEntry(le *logpb.LogEntry) (*logging.Entry, error) {
+ time, err := ptypes.Timestamp(le.Timestamp)
+ if err != nil {
+ return nil, err
+ }
+ var payload interface{}
+ switch x := le.Payload.(type) {
+ case *logpb.LogEntry_TextPayload:
+ payload = x.TextPayload
+
+ case *logpb.LogEntry_ProtoPayload:
+ var d ptypes.DynamicAny
+ if err := ptypes.UnmarshalAny(x.ProtoPayload, &d); err != nil {
+ return nil, fmt.Errorf("logging: unmarshalling proto payload: %v", err)
+ }
+ payload = d.Message
+
+ case *logpb.LogEntry_JsonPayload:
+ // Leave this as a Struct.
+ // TODO(jba): convert to map[string]interface{}?
+ payload = x.JsonPayload
+
+ default:
+ return nil, fmt.Errorf("logging: unknown payload type: %T", le.Payload)
+ }
+ hr, err := toHTTPRequest(le.HttpRequest)
+ if err != nil {
+ return nil, err
+ }
+ return &logging.Entry{
+ Timestamp: time,
+ Severity: logging.Severity(le.Severity),
+ Payload: payload,
+ Labels: le.Labels,
+ InsertID: le.InsertId,
+ HTTPRequest: hr,
+ Operation: le.Operation,
+ LogName: slashUnescaper.Replace(le.LogName),
+ Resource: le.Resource,
+ Trace: le.Trace,
+ }, nil
+}
+
+// Logs lists the logs owned by the parent resource of the client.
+func (c *Client) Logs(ctx context.Context) *LogIterator {
+ it := &LogIterator{
+ parentResource: c.parent(),
+ it: c.lClient.ListLogs(ctx, &logpb.ListLogsRequest{Parent: c.parent()}),
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ return it
+}
+
+// A LogIterator iterates over logs.
+type LogIterator struct {
+ parentResource string
+ it *vkit.StringIterator
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []string
+}
+
+// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details.
+func (it *LogIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is iterator.Done
+// (https://godoc.org/google.golang.org/api/iterator) if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *LogIterator) Next() (string, error) {
+ if err := it.nextFunc(); err != nil {
+ return "", err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *LogIterator) fetch(pageSize int, pageToken string) (string, error) {
+ return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
+ logPath, err := it.it.Next()
+ if err != nil {
+ return err
+ }
+ logID := internal.LogIDFromPath(it.parentResource, logPath)
+ it.items = append(it.items, logID)
+ return nil
+ })
+}
+
+// Common fetch code for iterators that are backed by vkit iterators.
+func iterFetch(pageSize int, pageToken string, pi *iterator.PageInfo, next func() error) (string, error) {
+ pi.MaxSize = pageSize
+ pi.Token = pageToken
+ // Get one item, which will fill the buffer.
+ if err := next(); err != nil {
+ return "", err
+ }
+ // Collect the rest of the buffer.
+ for pi.Remaining() > 0 {
+ if err := next(); err != nil {
+ return "", err
+ }
+ }
+ return pi.Token, nil
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go b/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go
new file mode 100644
index 000000000..1753f84f6
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go
@@ -0,0 +1,274 @@
+// 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.
+
+// TODO(jba): test that OnError is getting called appropriately.
+
+package logadmin
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "reflect"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/internal/testutil"
+ "cloud.google.com/go/logging"
+ ltesting "cloud.google.com/go/logging/internal/testing"
+ "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/ptypes"
+ durpb "github.com/golang/protobuf/ptypes/duration"
+ structpb "github.com/golang/protobuf/ptypes/struct"
+ "golang.org/x/net/context"
+ "google.golang.org/api/option"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ audit "google.golang.org/genproto/googleapis/cloud/audit"
+ logtypepb "google.golang.org/genproto/googleapis/logging/type"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+ "google.golang.org/grpc"
+)
+
+var (
+ client *Client
+ testProjectID string
+)
+
+var (
+ // If true, this test is using the production service, not a fake.
+ integrationTest bool
+
+ newClient func(ctx context.Context, projectID string) *Client
+)
+
+func TestMain(m *testing.M) {
+ flag.Parse() // needed for testing.Short()
+ ctx := context.Background()
+ testProjectID = testutil.ProjID()
+ if testProjectID == "" || testing.Short() {
+ integrationTest = false
+ if testProjectID != "" {
+ log.Print("Integration tests skipped in short mode (using fake instead)")
+ }
+ testProjectID = "PROJECT_ID"
+ addr, err := ltesting.NewServer()
+ if err != nil {
+ log.Fatalf("creating fake server: %v", err)
+ }
+ newClient = func(ctx context.Context, projectID string) *Client {
+ conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock())
+ if err != nil {
+ log.Fatalf("dialing %q: %v", addr, err)
+ }
+ c, err := NewClient(ctx, projectID, option.WithGRPCConn(conn))
+ if err != nil {
+ log.Fatalf("creating client for fake at %q: %v", addr, err)
+ }
+ return c
+ }
+ } else {
+ integrationTest = true
+ ts := testutil.TokenSource(ctx, logging.AdminScope)
+ if ts == nil {
+ log.Fatal("The project key must be set. See CONTRIBUTING.md for details")
+ }
+ log.Printf("running integration tests with project %s", testProjectID)
+ newClient = func(ctx context.Context, projectID string) *Client {
+ c, err := NewClient(ctx, projectID, option.WithTokenSource(ts),
+ option.WithGRPCDialOption(grpc.WithBlock()))
+ if err != nil {
+ log.Fatalf("creating prod client: %v", err)
+ }
+ return c
+ }
+ }
+ client = newClient(ctx, testProjectID)
+ initMetrics(ctx)
+ cleanup := initSinks(ctx)
+ exit := m.Run()
+ cleanup()
+ client.Close()
+ os.Exit(exit)
+}
+
+// EntryIterator and DeleteLog are tested in the logging package.
+
+func TestClientClose(t *testing.T) {
+ c := newClient(context.Background(), testProjectID)
+ if err := c.Close(); err != nil {
+ t.Errorf("want got %v, want nil", err)
+ }
+}
+
+func TestFromLogEntry(t *testing.T) {
+ now := time.Now()
+ res := &mrpb.MonitoredResource{Type: "global"}
+ ts, err := ptypes.TimestampProto(now)
+ if err != nil {
+ t.Fatal(err)
+ }
+ logEntry := logpb.LogEntry{
+ LogName: "projects/PROJECT_ID/logs/LOG_ID",
+ Resource: res,
+ Payload: &logpb.LogEntry_TextPayload{TextPayload: "hello"},
+ Timestamp: ts,
+ Severity: logtypepb.LogSeverity_INFO,
+ InsertId: "123",
+ HttpRequest: &logtypepb.HttpRequest{
+ RequestMethod: "GET",
+ RequestUrl: "http:://example.com/path?q=1",
+ RequestSize: 100,
+ Status: 200,
+ ResponseSize: 25,
+ Latency: &durpb.Duration{Seconds: 100},
+ UserAgent: "user-agent",
+ RemoteIp: "127.0.0.1",
+ Referer: "referer",
+ CacheHit: true,
+ CacheValidatedWithOriginServer: true,
+ },
+ Labels: map[string]string{
+ "a": "1",
+ "b": "two",
+ "c": "true",
+ },
+ }
+ u, err := url.Parse("http:://example.com/path?q=1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := &logging.Entry{
+ LogName: "projects/PROJECT_ID/logs/LOG_ID",
+ Resource: res,
+ Timestamp: now.In(time.UTC),
+ Severity: logging.Info,
+ Payload: "hello",
+ Labels: map[string]string{
+ "a": "1",
+ "b": "two",
+ "c": "true",
+ },
+ InsertID: "123",
+ HTTPRequest: &logging.HTTPRequest{
+ Request: &http.Request{
+ Method: "GET",
+ URL: u,
+ Header: map[string][]string{
+ "User-Agent": []string{"user-agent"},
+ "Referer": []string{"referer"},
+ },
+ },
+ RequestSize: 100,
+ Status: 200,
+ ResponseSize: 25,
+ Latency: 100 * time.Second,
+ RemoteIP: "127.0.0.1",
+ CacheHit: true,
+ CacheValidatedWithOriginServer: true,
+ },
+ }
+ got, err := fromLogEntry(&logEntry)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Test sub-values separately because %+v and %#v do not follow pointers.
+ // TODO(jba): use a differ or pretty-printer.
+ if !reflect.DeepEqual(got.HTTPRequest.Request, want.HTTPRequest.Request) {
+ t.Fatalf("HTTPRequest.Request:\ngot %+v\nwant %+v", got.HTTPRequest.Request, want.HTTPRequest.Request)
+ }
+ if !reflect.DeepEqual(got.HTTPRequest, want.HTTPRequest) {
+ t.Fatalf("HTTPRequest:\ngot %+v\nwant %+v", got.HTTPRequest, want.HTTPRequest)
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("FullEntry:\ngot %+v\nwant %+v", got, want)
+ }
+
+ // Proto payload.
+ alog := &audit.AuditLog{
+ ServiceName: "svc",
+ MethodName: "method",
+ ResourceName: "shelves/S/books/B",
+ }
+ any, err := ptypes.MarshalAny(alog)
+ if err != nil {
+ t.Fatal(err)
+ }
+ logEntry = logpb.LogEntry{
+ LogName: "projects/PROJECT_ID/logs/LOG_ID",
+ Resource: res,
+ Timestamp: ts,
+ Payload: &logpb.LogEntry_ProtoPayload{ProtoPayload: any},
+ }
+ got, err = fromLogEntry(&logEntry)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !ltesting.PayloadEqual(got.Payload, alog) {
+ t.Errorf("got %+v, want %+v", got.Payload, alog)
+ }
+
+ // JSON payload.
+ jstruct := &structpb.Struct{Fields: map[string]*structpb.Value{
+ "f": &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: 3.1}},
+ }}
+ logEntry = logpb.LogEntry{
+ LogName: "projects/PROJECT_ID/logs/LOG_ID",
+ Resource: res,
+ Timestamp: ts,
+ Payload: &logpb.LogEntry_JsonPayload{JsonPayload: jstruct},
+ }
+ got, err = fromLogEntry(&logEntry)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !ltesting.PayloadEqual(got.Payload, jstruct) {
+ t.Errorf("got %+v, want %+v", got.Payload, jstruct)
+ }
+}
+
+func TestListLogEntriesRequest(t *testing.T) {
+ for _, test := range []struct {
+ opts []EntriesOption
+ projectIDs []string
+ filter string
+ orderBy string
+ }{
+ // Default is client's project ID, empty filter and orderBy.
+ {nil,
+ []string{"PROJECT_ID"}, "", ""},
+ {[]EntriesOption{NewestFirst(), Filter("f")},
+ []string{"PROJECT_ID"}, "f", "timestamp desc"},
+ {[]EntriesOption{ProjectIDs([]string{"foo"})},
+ []string{"foo"}, "", ""},
+ {[]EntriesOption{NewestFirst(), Filter("f"), ProjectIDs([]string{"foo"})},
+ []string{"foo"}, "f", "timestamp desc"},
+ {[]EntriesOption{NewestFirst(), Filter("f"), ProjectIDs([]string{"foo"})},
+ []string{"foo"}, "f", "timestamp desc"},
+ // If there are repeats, last one wins.
+ {[]EntriesOption{NewestFirst(), Filter("no"), ProjectIDs([]string{"foo"}), Filter("f")},
+ []string{"foo"}, "f", "timestamp desc"},
+ } {
+ got := listLogEntriesRequest("PROJECT_ID", test.opts)
+ want := &logpb.ListLogEntriesRequest{
+ ResourceNames: []string{"projects/" + test.projectIDs[0]},
+ Filter: test.filter,
+ OrderBy: test.orderBy,
+ }
+ if !proto.Equal(got, want) {
+ t.Errorf("%v:\ngot %v\nwant %v", test.opts, got, want)
+ }
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/metrics.go b/vendor/cloud.google.com/go/logging/logadmin/metrics.go
new file mode 100644
index 000000000..9374ac46a
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/metrics.go
@@ -0,0 +1,154 @@
+// 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 logadmin
+
+import (
+ "fmt"
+
+ vkit "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+// Metric describes a logs-based metric. The value of the metric is the
+// number of log entries that match a logs filter.
+//
+// Metrics are a feature of Stackdriver Monitoring.
+// See https://cloud.google.com/monitoring/api/v3/metrics for more about them.
+type Metric struct {
+ // ID is a client-assigned metric identifier. Example:
+ // "severe_errors". Metric identifiers are limited to 1000
+ // characters and can include only the following characters: A-Z,
+ // a-z, 0-9, and the special characters _-.,+!*',()%/\. The
+ // forward-slash character (/) denotes a hierarchy of name pieces,
+ // and it cannot be the first character of the name.
+ ID string
+
+ // Description describes this metric. It is used in documentation.
+ Description string
+
+ // Filter is an advanced logs filter (see
+ // https://cloud.google.com/logging/docs/view/advanced_filters).
+ // Example: "logName:syslog AND severity>=ERROR".
+ Filter string
+}
+
+// CreateMetric creates a logs-based metric.
+func (c *Client) CreateMetric(ctx context.Context, m *Metric) error {
+ _, err := c.mClient.CreateLogMetric(ctx, &logpb.CreateLogMetricRequest{
+ Parent: c.parent(),
+ Metric: toLogMetric(m),
+ })
+ return err
+}
+
+// DeleteMetric deletes a log-based metric.
+// The provided metric ID is the metric identifier. For example, "severe_errors".
+func (c *Client) DeleteMetric(ctx context.Context, metricID string) error {
+ return c.mClient.DeleteLogMetric(ctx, &logpb.DeleteLogMetricRequest{
+ MetricName: c.metricPath(metricID),
+ })
+}
+
+// Metric gets a logs-based metric.
+// The provided metric ID is the metric identifier. For example, "severe_errors".
+// Requires ReadScope or AdminScope.
+func (c *Client) Metric(ctx context.Context, metricID string) (*Metric, error) {
+ lm, err := c.mClient.GetLogMetric(ctx, &logpb.GetLogMetricRequest{
+ MetricName: c.metricPath(metricID),
+ })
+ if err != nil {
+ return nil, err
+ }
+ return fromLogMetric(lm), nil
+}
+
+// UpdateMetric creates a logs-based metric if it does not exist, or updates an
+// existing one.
+func (c *Client) UpdateMetric(ctx context.Context, m *Metric) error {
+ _, err := c.mClient.UpdateLogMetric(ctx, &logpb.UpdateLogMetricRequest{
+ MetricName: c.metricPath(m.ID),
+ Metric: toLogMetric(m),
+ })
+ return err
+}
+
+func (c *Client) metricPath(metricID string) string {
+ return fmt.Sprintf("%s/metrics/%s", c.parent(), metricID)
+}
+
+// Metrics returns a MetricIterator for iterating over all Metrics in the Client's project.
+// Requires ReadScope or AdminScope.
+func (c *Client) Metrics(ctx context.Context) *MetricIterator {
+ it := &MetricIterator{
+ it: c.mClient.ListLogMetrics(ctx, &logpb.ListLogMetricsRequest{Parent: c.parent()}),
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ return it
+}
+
+// A MetricIterator iterates over Metrics.
+type MetricIterator struct {
+ it *vkit.LogMetricIterator
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []*Metric
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *MetricIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is Done if there are
+// no more results. Once Next returns Done, all subsequent calls will return
+// Done.
+func (it *MetricIterator) Next() (*Metric, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *MetricIterator) fetch(pageSize int, pageToken string) (string, error) {
+ return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
+ item, err := it.it.Next()
+ if err != nil {
+ return err
+ }
+ it.items = append(it.items, fromLogMetric(item))
+ return nil
+ })
+}
+
+func toLogMetric(m *Metric) *logpb.LogMetric {
+ return &logpb.LogMetric{
+ Name: m.ID,
+ Description: m.Description,
+ Filter: m.Filter,
+ }
+}
+
+func fromLogMetric(lm *logpb.LogMetric) *Metric {
+ return &Metric{
+ ID: lm.Name,
+ Description: lm.Description,
+ Filter: lm.Filter,
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go b/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go
new file mode 100644
index 000000000..f3f148e1b
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go
@@ -0,0 +1,155 @@
+// 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 logadmin
+
+import (
+ "log"
+ "reflect"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/internal/testutil"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+var metricIDs = testutil.NewUIDSpace("GO-CLIENT-TEST-METRIC")
+
+// Initializes the tests before they run.
+func initMetrics(ctx context.Context) {
+ // Clean up from aborted tests.
+ it := client.Metrics(ctx)
+loop:
+ for {
+ m, err := it.Next()
+ switch err {
+ case nil:
+ if metricIDs.Older(m.ID, 24*time.Hour) {
+ client.DeleteMetric(ctx, m.ID)
+ }
+ case iterator.Done:
+ break loop
+ default:
+ log.Printf("cleanupMetrics: %v", err)
+ return
+ }
+ }
+}
+
+func TestCreateDeleteMetric(t *testing.T) {
+ ctx := context.Background()
+ metric := &Metric{
+ ID: metricIDs.New(),
+ Description: "DESC",
+ Filter: "FILTER",
+ }
+ if err := client.CreateMetric(ctx, metric); err != nil {
+ t.Fatal(err)
+ }
+ defer client.DeleteMetric(ctx, metric.ID)
+
+ got, err := client.Metric(ctx, metric.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := metric; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+
+ if err := client.DeleteMetric(ctx, metric.ID); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := client.Metric(ctx, metric.ID); err == nil {
+ t.Fatal("got no error, expected one")
+ }
+}
+
+func TestUpdateMetric(t *testing.T) {
+ ctx := context.Background()
+ metric := &Metric{
+ ID: metricIDs.New(),
+ Description: "DESC",
+ Filter: "FILTER",
+ }
+
+ // Updating a non-existent metric creates a new one.
+ if err := client.UpdateMetric(ctx, metric); err != nil {
+ t.Fatal(err)
+ }
+ defer client.DeleteMetric(ctx, metric.ID)
+ got, err := client.Metric(ctx, metric.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := metric; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+
+ // Updating an existing metric changes it.
+ metric.Description = "CHANGED"
+ if err := client.UpdateMetric(ctx, metric); err != nil {
+ t.Fatal(err)
+ }
+ got, err = client.Metric(ctx, metric.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := metric; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+}
+
+func TestListMetrics(t *testing.T) {
+ ctx := context.Background()
+
+ var metrics []*Metric
+ want := map[string]*Metric{}
+ for i := 0; i < 10; i++ {
+ m := &Metric{
+ ID: metricIDs.New(),
+ Description: "DESC",
+ Filter: "FILTER",
+ }
+ metrics = append(metrics, m)
+ want[m.ID] = m
+ }
+ for _, m := range metrics {
+ if err := client.CreateMetric(ctx, m); err != nil {
+ t.Fatalf("Create(%q): %v", m.ID, err)
+ }
+ defer client.DeleteMetric(ctx, m.ID)
+ }
+
+ got := map[string]*Metric{}
+ it := client.Metrics(ctx)
+ for {
+ m, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ // If tests run simultaneously, we may have more metrics than we
+ // created. So only check for our own.
+ if _, ok := want[m.ID]; ok {
+ got[m.ID] = m
+ }
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/resources.go b/vendor/cloud.google.com/go/logging/logadmin/resources.go
new file mode 100644
index 000000000..79e8fdbc9
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/resources.go
@@ -0,0 +1,74 @@
+// 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 logadmin
+
+import (
+ vkit "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+// ResourceDescriptors returns a ResourceDescriptorIterator
+// for iterating over MonitoredResourceDescriptors. Requires ReadScope or AdminScope.
+// See https://cloud.google.com/logging/docs/api/v2/#monitored-resources for an explanation of
+// monitored resources.
+// See https://cloud.google.com/logging/docs/api/v2/resource-list for a list of monitored resources.
+func (c *Client) ResourceDescriptors(ctx context.Context) *ResourceDescriptorIterator {
+ it := &ResourceDescriptorIterator{
+ it: c.lClient.ListMonitoredResourceDescriptors(ctx,
+ &logpb.ListMonitoredResourceDescriptorsRequest{}),
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ return it
+}
+
+// ResourceDescriptorIterator is an iterator over MonitoredResourceDescriptors.
+type ResourceDescriptorIterator struct {
+ it *vkit.MonitoredResourceDescriptorIterator
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []*mrpb.MonitoredResourceDescriptor
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *ResourceDescriptorIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is Done if there are
+// no more results. Once Next returns Done, all subsequent calls will return
+// Done.
+func (it *ResourceDescriptorIterator) Next() (*mrpb.MonitoredResourceDescriptor, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *ResourceDescriptorIterator) fetch(pageSize int, pageToken string) (string, error) {
+ return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
+ item, err := it.it.Next()
+ if err != nil {
+ return err
+ }
+ it.items = append(it.items, item)
+ return nil
+ })
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/resources_test.go b/vendor/cloud.google.com/go/logging/logadmin/resources_test.go
new file mode 100644
index 000000000..067d3d7ab
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/resources_test.go
@@ -0,0 +1,46 @@
+// 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 logadmin
+
+import (
+ "testing"
+
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+)
+
+func TestMonitoredResourceDescriptors(t *testing.T) {
+ // We can't create MonitoredResourceDescriptors, and there is no guarantee
+ // about what the service will return. So we just check that the result is
+ // non-empty.
+ it := client.ResourceDescriptors(context.Background())
+ n := 0
+loop:
+ for {
+ _, err := it.Next()
+ switch err {
+ case nil:
+ n++
+ case iterator.Done:
+ break loop
+ default:
+ t.Fatal(err)
+ }
+ }
+ if n == 0 {
+ t.Fatal("Next: got no MetricResourceDescriptors, expected at least one")
+ }
+ // TODO(jba) test pagination.
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/sinks.go b/vendor/cloud.google.com/go/logging/logadmin/sinks.go
new file mode 100644
index 000000000..588c7afd3
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/sinks.go
@@ -0,0 +1,169 @@
+// 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 logadmin
+
+import (
+ "fmt"
+
+ vkit "cloud.google.com/go/logging/apiv2"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+// Sink describes a sink used to export log entries outside Stackdriver
+// Logging. Incoming log entries matching a filter are exported to a
+// destination (a Cloud Storage bucket, BigQuery dataset or Cloud Pub/Sub
+// topic).
+//
+// For more information, see https://cloud.google.com/logging/docs/export/using_exported_logs.
+// (The Sinks in this package are what the documentation refers to as "project sinks".)
+type Sink struct {
+ // ID is a client-assigned sink identifier. Example:
+ // "my-severe-errors-to-pubsub".
+ // Sink identifiers are limited to 1000 characters
+ // and can include only the following characters: A-Z, a-z,
+ // 0-9, and the special characters "_-.".
+ ID string
+
+ // Destination is the export destination. See
+ // https://cloud.google.com/logging/docs/api/tasks/exporting-logs.
+ // Examples: "storage.googleapis.com/a-bucket",
+ // "bigquery.googleapis.com/projects/a-project-id/datasets/a-dataset".
+ Destination string
+
+ // Filter optionally specifies an advanced logs filter (see
+ // https://cloud.google.com/logging/docs/view/advanced_filters) that
+ // defines the log entries to be exported. Example: "logName:syslog AND
+ // severity>=ERROR". If omitted, all entries are returned.
+ Filter string
+}
+
+// CreateSink creates a Sink. It returns an error if the Sink already exists.
+// Requires AdminScope.
+func (c *Client) CreateSink(ctx context.Context, sink *Sink) (*Sink, error) {
+ ls, err := c.sClient.CreateSink(ctx, &logpb.CreateSinkRequest{
+ Parent: c.parent(),
+ Sink: toLogSink(sink),
+ })
+ if err != nil {
+ fmt.Printf("Sink: %+v\n", toLogSink(sink))
+ return nil, err
+ }
+ return fromLogSink(ls), nil
+}
+
+// DeleteSink deletes a sink. The provided sinkID is the sink's identifier, such as
+// "my-severe-errors-to-pubsub".
+// Requires AdminScope.
+func (c *Client) DeleteSink(ctx context.Context, sinkID string) error {
+ return c.sClient.DeleteSink(ctx, &logpb.DeleteSinkRequest{
+ SinkName: c.sinkPath(sinkID),
+ })
+}
+
+// Sink gets a sink. The provided sinkID is the sink's identifier, such as
+// "my-severe-errors-to-pubsub".
+// Requires ReadScope or AdminScope.
+func (c *Client) Sink(ctx context.Context, sinkID string) (*Sink, error) {
+ ls, err := c.sClient.GetSink(ctx, &logpb.GetSinkRequest{
+ SinkName: c.sinkPath(sinkID),
+ })
+ if err != nil {
+ return nil, err
+ }
+ return fromLogSink(ls), nil
+}
+
+// UpdateSink updates an existing Sink, or creates a new one if the Sink doesn't exist.
+// Requires AdminScope.
+func (c *Client) UpdateSink(ctx context.Context, sink *Sink) (*Sink, error) {
+ ls, err := c.sClient.UpdateSink(ctx, &logpb.UpdateSinkRequest{
+ SinkName: c.sinkPath(sink.ID),
+ Sink: toLogSink(sink),
+ })
+ if err != nil {
+ return nil, err
+ }
+ return fromLogSink(ls), err
+}
+
+func (c *Client) sinkPath(sinkID string) string {
+ return fmt.Sprintf("%s/sinks/%s", c.parent(), sinkID)
+}
+
+// Sinks returns a SinkIterator for iterating over all Sinks in the Client's project.
+// Requires ReadScope or AdminScope.
+func (c *Client) Sinks(ctx context.Context) *SinkIterator {
+ it := &SinkIterator{
+ it: c.sClient.ListSinks(ctx, &logpb.ListSinksRequest{Parent: c.parent()}),
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ return it
+}
+
+// A SinkIterator iterates over Sinks.
+type SinkIterator struct {
+ it *vkit.LogSinkIterator
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []*Sink
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *SinkIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is Done if there are
+// no more results. Once Next returns Done, all subsequent calls will return
+// Done.
+func (it *SinkIterator) Next() (*Sink, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *SinkIterator) fetch(pageSize int, pageToken string) (string, error) {
+ return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
+ item, err := it.it.Next()
+ if err != nil {
+ return err
+ }
+ it.items = append(it.items, fromLogSink(item))
+ return nil
+ })
+}
+
+func toLogSink(s *Sink) *logpb.LogSink {
+ return &logpb.LogSink{
+ Name: s.ID,
+ Destination: s.Destination,
+ Filter: s.Filter,
+ OutputVersionFormat: logpb.LogSink_V2,
+ }
+}
+
+func fromLogSink(ls *logpb.LogSink) *Sink {
+ return &Sink{
+ ID: ls.Name,
+ Destination: ls.Destination,
+ Filter: ls.Filter,
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go b/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go
new file mode 100644
index 000000000..a75125303
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go
@@ -0,0 +1,226 @@
+// 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.
+
+// TODO(jba): document in CONTRIBUTING.md that service account must be given "Logs Configuration Writer" IAM role for sink tests to pass.
+// TODO(jba): [cont] (1) From top left menu, go to IAM & Admin. (2) In Roles dropdown for acct, select Logging > Logs Configuration Writer. (3) Save.
+// TODO(jba): Also, cloud-logs@google.com must have Owner permission on the GCS bucket named for the test project.
+
+package logadmin
+
+import (
+ "log"
+ "reflect"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/internal/testutil"
+ "cloud.google.com/go/storage"
+ "golang.org/x/net/context"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+)
+
+var sinkIDs = testutil.NewUIDSpace("GO-CLIENT-TEST-SINK")
+
+const testFilter = ""
+
+var testSinkDestination string
+
+// Called just before TestMain calls m.Run.
+// Returns a cleanup function to be called after the tests finish.
+func initSinks(ctx context.Context) func() {
+ // Create a unique GCS bucket so concurrent tests don't interfere with each other.
+ bucketIDs := testutil.NewUIDSpace(testProjectID + "-log-sink")
+ testBucket := bucketIDs.New()
+ testSinkDestination = "storage.googleapis.com/" + testBucket
+ var storageClient *storage.Client
+ if integrationTest {
+ // Create a unique bucket as a sink destination, and give the cloud logging account
+ // owner right.
+ ts := testutil.TokenSource(ctx, storage.ScopeFullControl)
+ var err error
+ storageClient, err = storage.NewClient(ctx, option.WithTokenSource(ts))
+ if err != nil {
+ log.Fatalf("new storage client: %v", err)
+ }
+ bucket := storageClient.Bucket(testBucket)
+ if err := bucket.Create(ctx, testProjectID, nil); err != nil {
+ log.Fatalf("creating storage bucket %q: %v", testBucket, err)
+ }
+ if err := bucket.ACL().Set(ctx, "group-cloud-logs@google.com", storage.RoleOwner); err != nil {
+ log.Fatalf("setting owner role: %v", err)
+ }
+ }
+ // Clean up from aborted tests.
+ it := client.Sinks(ctx)
+ for {
+ s, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ log.Printf("listing sinks: %v", err)
+ break
+ }
+ if sinkIDs.Older(s.ID, 24*time.Hour) {
+ client.DeleteSink(ctx, s.ID) // ignore error
+ }
+ }
+ if integrationTest {
+ for _, bn := range bucketNames(ctx, storageClient) {
+ if bucketIDs.Older(bn, 24*time.Hour) {
+ storageClient.Bucket(bn).Delete(ctx) // ignore error
+ }
+ }
+ return func() {
+ if err := storageClient.Bucket(testBucket).Delete(ctx); err != nil {
+ log.Printf("deleting %q: %v", testBucket, err)
+ }
+ storageClient.Close()
+ }
+ }
+ return func() {}
+}
+
+// Collect the name of all buckets for the test project.
+func bucketNames(ctx context.Context, client *storage.Client) []string {
+ var names []string
+ it := client.Buckets(ctx, testProjectID)
+loop:
+ for {
+ b, err := it.Next()
+ switch err {
+ case nil:
+ names = append(names, b.Name)
+ case iterator.Done:
+ break loop
+ default:
+ log.Printf("listing buckets: %v", err)
+ break loop
+ }
+ }
+ return names
+}
+
+func TestCreateDeleteSink(t *testing.T) {
+ ctx := context.Background()
+ sink := &Sink{
+ ID: sinkIDs.New(),
+ Destination: testSinkDestination,
+ Filter: testFilter,
+ }
+ got, err := client.CreateSink(ctx, sink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer client.DeleteSink(ctx, sink.ID)
+ if want := sink; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+ got, err = client.Sink(ctx, sink.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := sink; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+
+ if err := client.DeleteSink(ctx, sink.ID); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := client.Sink(ctx, sink.ID); err == nil {
+ t.Fatal("got no error, expected one")
+ }
+}
+
+func TestUpdateSink(t *testing.T) {
+ ctx := context.Background()
+ sink := &Sink{
+ ID: sinkIDs.New(),
+ Destination: testSinkDestination,
+ Filter: testFilter,
+ }
+
+ // Updating a non-existent sink creates a new one.
+ got, err := client.UpdateSink(ctx, sink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer client.DeleteSink(ctx, sink.ID)
+ if want := sink; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+ got, err = client.Sink(ctx, sink.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := sink; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+
+ // Updating an existing sink changes it.
+ sink.Filter = ""
+ if _, err := client.UpdateSink(ctx, sink); err != nil {
+ t.Fatal(err)
+ }
+ got, err = client.Sink(ctx, sink.ID)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want := sink; !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+}
+
+func TestListSinks(t *testing.T) {
+ ctx := context.Background()
+ var sinks []*Sink
+ want := map[string]*Sink{}
+ for i := 0; i < 4; i++ {
+ s := &Sink{
+ ID: sinkIDs.New(),
+ Destination: testSinkDestination,
+ Filter: testFilter,
+ }
+ sinks = append(sinks, s)
+ want[s.ID] = s
+ }
+ for _, s := range sinks {
+ if _, err := client.CreateSink(ctx, s); err != nil {
+ t.Fatalf("Create(%q): %v", s.ID, err)
+ }
+ defer client.DeleteSink(ctx, s.ID)
+ }
+
+ got := map[string]*Sink{}
+ it := client.Sinks(ctx)
+ for {
+ s, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ // If tests run simultaneously, we may have more sinks than we
+ // created. So only check for our own.
+ if _, ok := want[s.ID]; ok {
+ got[s.ID] = s
+ }
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+}
diff --git a/vendor/cloud.google.com/go/logging/logging.go b/vendor/cloud.google.com/go/logging/logging.go
new file mode 100644
index 000000000..4792db682
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logging.go
@@ -0,0 +1,738 @@
+// 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.
+
+// API/gRPC features intentionally missing from this client:
+// - You cannot have the server pick the time of the entry. This client
+// always sends a time.
+// - There is no way to provide a protocol buffer payload.
+// - No support for the "partial success" feature when writing log entries.
+
+// TODO(jba): test whether forward-slash characters in the log ID must be URL-encoded.
+// These features are missing now, but will likely be added:
+// - There is no way to specify CallOptions.
+
+package logging
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "math"
+ "net/http"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "cloud.google.com/go/compute/metadata"
+ "cloud.google.com/go/internal/version"
+ vkit "cloud.google.com/go/logging/apiv2"
+ "cloud.google.com/go/logging/internal"
+ "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/ptypes"
+ structpb "github.com/golang/protobuf/ptypes/struct"
+ tspb "github.com/golang/protobuf/ptypes/timestamp"
+ "golang.org/x/net/context"
+ "google.golang.org/api/option"
+ "google.golang.org/api/support/bundler"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ logtypepb "google.golang.org/genproto/googleapis/logging/type"
+ logpb "google.golang.org/genproto/googleapis/logging/v2"
+)
+
+const (
+ // Scope for reading from the logging service.
+ ReadScope = "https://www.googleapis.com/auth/logging.read"
+
+ // Scope for writing to the logging service.
+ WriteScope = "https://www.googleapis.com/auth/logging.write"
+
+ // Scope for administrative actions on the logging service.
+ AdminScope = "https://www.googleapis.com/auth/logging.admin"
+)
+
+const (
+ // defaultErrorCapacity is the capacity of the channel used to deliver
+ // errors to the OnError function.
+ defaultErrorCapacity = 10
+
+ // DefaultDelayThreshold is the default value for the DelayThreshold LoggerOption.
+ DefaultDelayThreshold = time.Second
+
+ // DefaultEntryCountThreshold is the default value for the EntryCountThreshold LoggerOption.
+ DefaultEntryCountThreshold = 1000
+
+ // DefaultEntryByteThreshold is the default value for the EntryByteThreshold LoggerOption.
+ DefaultEntryByteThreshold = 1 << 20 // 1MiB
+
+ // DefaultBufferedByteLimit is the default value for the BufferedByteLimit LoggerOption.
+ DefaultBufferedByteLimit = 1 << 30 // 1GiB
+)
+
+// For testing:
+var now = time.Now
+
+// ErrOverflow signals that the number of buffered entries for a Logger
+// exceeds its BufferLimit.
+var ErrOverflow = errors.New("logging: log entry overflowed buffer limits")
+
+// Client is a Logging client. A Client is associated with a single Cloud project.
+type Client struct {
+ client *vkit.Client // client for the logging service
+ projectID string
+ errc chan error // should be buffered to minimize dropped errors
+ donec chan struct{} // closed on Client.Close to close Logger bundlers
+ loggers sync.WaitGroup // so we can wait for loggers to close
+ closed bool
+
+ // OnError is called when an error occurs in a call to Log or Flush. The
+ // error may be due to an invalid Entry, an overflow because BufferLimit
+ // was reached (in which case the error will be ErrOverflow) or an error
+ // communicating with the logging service. OnError is called with errors
+ // from all Loggers. It is never called concurrently. OnError is expected
+ // to return quickly; if errors occur while OnError is running, some may
+ // not be reported. The default behavior is to call log.Printf.
+ //
+ // This field should be set only once, before any method of Client is called.
+ OnError func(err error)
+}
+
+// NewClient returns a new logging client associated with the provided project ID.
+//
+// By default NewClient uses WriteScope. To use a different scope, call
+// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes).
+func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
+ // Check for '/' in project ID to reserve the ability to support various owning resources,
+ // in the form "{Collection}/{Name}", for instance "organizations/my-org".
+ if strings.ContainsRune(projectID, '/') {
+ return nil, errors.New("logging: project ID contains '/'")
+ }
+ opts = append([]option.ClientOption{
+ option.WithEndpoint(internal.ProdAddr),
+ option.WithScopes(WriteScope),
+ }, opts...)
+ c, err := vkit.NewClient(ctx, opts...)
+ if err != nil {
+ return nil, err
+ }
+ c.SetGoogleClientInfo("gccl", version.Repo)
+ client := &Client{
+ client: c,
+ projectID: projectID,
+ errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors
+ donec: make(chan struct{}),
+ OnError: func(e error) { log.Printf("logging client: %v", e) },
+ }
+ // Call the user's function synchronously, to make life easier for them.
+ go func() {
+ for err := range client.errc {
+ // This reference to OnError is memory-safe if the user sets OnError before
+ // calling any client methods. The reference happens before the first read from
+ // client.errc, which happens before the first write to client.errc, which
+ // happens before any call, which happens before the user sets OnError.
+ if fn := client.OnError; fn != nil {
+ fn(err)
+ } else {
+ log.Printf("logging (project ID %q): %v", projectID, err)
+ }
+ }
+ }()
+ return client, nil
+}
+
+// parent returns the string used in many RPCs to denote the parent resource of the log.
+func (c *Client) parent() string {
+ return "projects/" + c.projectID
+}
+
+var unixZeroTimestamp *tspb.Timestamp
+
+func init() {
+ var err error
+ unixZeroTimestamp, err = ptypes.TimestampProto(time.Unix(0, 0))
+ if err != nil {
+ panic(err)
+ }
+}
+
+// Ping reports whether the client's connection to the logging service and the
+// authentication configuration are valid. To accomplish this, Ping writes a
+// log entry "ping" to a log named "ping".
+func (c *Client) Ping(ctx context.Context) error {
+ ent := &logpb.LogEntry{
+ Payload: &logpb.LogEntry_TextPayload{TextPayload: "ping"},
+ Timestamp: unixZeroTimestamp, // Identical timestamps and insert IDs are both
+ InsertId: "ping", // necessary for the service to dedup these entries.
+ }
+ _, err := c.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
+ LogName: internal.LogPath(c.parent(), "ping"),
+ Resource: globalResource(c.projectID),
+ Entries: []*logpb.LogEntry{ent},
+ })
+ return err
+}
+
+// A Logger is used to write log messages to a single log. It can be configured
+// with a log ID, common monitored resource, and a set of common labels.
+type Logger struct {
+ client *Client
+ logName string // "projects/{projectID}/logs/{logID}"
+ stdLoggers map[Severity]*log.Logger
+ bundler *bundler.Bundler
+
+ // Options
+ commonResource *mrpb.MonitoredResource
+ commonLabels map[string]string
+}
+
+// A LoggerOption is a configuration option for a Logger.
+type LoggerOption interface {
+ set(*Logger)
+}
+
+// CommonResource sets the monitored resource associated with all log entries
+// written from a Logger. If not provided, the resource is automatically
+// detected based on the running environment. This value can be overridden
+// per-entry by setting an Entry's Resource field.
+func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} }
+
+type commonResource struct{ *mrpb.MonitoredResource }
+
+func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource }
+
+var detectedResource struct {
+ pb *mrpb.MonitoredResource
+ once sync.Once
+}
+
+func detectResource() *mrpb.MonitoredResource {
+ detectedResource.once.Do(func() {
+ if !metadata.OnGCE() {
+ return
+ }
+ projectID, err := metadata.ProjectID()
+ if err != nil {
+ return
+ }
+ id, err := metadata.InstanceID()
+ if err != nil {
+ return
+ }
+ zone, err := metadata.Zone()
+ if err != nil {
+ return
+ }
+ detectedResource.pb = &mrpb.MonitoredResource{
+ Type: "gce_instance",
+ Labels: map[string]string{
+ "project_id": projectID,
+ "instance_id": id,
+ "zone": zone,
+ },
+ }
+ })
+ return detectedResource.pb
+}
+
+func globalResource(projectID string) *mrpb.MonitoredResource {
+ return &mrpb.MonitoredResource{
+ Type: "global",
+ Labels: map[string]string{
+ "project_id": projectID,
+ },
+ }
+}
+
+// CommonLabels are labels that apply to all log entries written from a Logger,
+// so that you don't have to repeat them in each log entry's Labels field. If
+// any of the log entries contains a (key, value) with the same key that is in
+// CommonLabels, then the entry's (key, value) overrides the one in
+// CommonLabels.
+func CommonLabels(m map[string]string) LoggerOption { return commonLabels(m) }
+
+type commonLabels map[string]string
+
+func (c commonLabels) set(l *Logger) { l.commonLabels = c }
+
+// DelayThreshold is the maximum amount of time that an entry should remain
+// buffered in memory before a call to the logging service is triggered. Larger
+// values of DelayThreshold will generally result in fewer calls to the logging
+// service, while increasing the risk that log entries will be lost if the
+// process crashes.
+// The default is DefaultDelayThreshold.
+func DelayThreshold(d time.Duration) LoggerOption { return delayThreshold(d) }
+
+type delayThreshold time.Duration
+
+func (d delayThreshold) set(l *Logger) { l.bundler.DelayThreshold = time.Duration(d) }
+
+// EntryCountThreshold is the maximum number of entries that will be buffered
+// in memory before a call to the logging service is triggered. Larger values
+// will generally result in fewer calls to the logging service, while
+// increasing both memory consumption and the risk that log entries will be
+// lost if the process crashes.
+// The default is DefaultEntryCountThreshold.
+func EntryCountThreshold(n int) LoggerOption { return entryCountThreshold(n) }
+
+type entryCountThreshold int
+
+func (e entryCountThreshold) set(l *Logger) { l.bundler.BundleCountThreshold = int(e) }
+
+// EntryByteThreshold is the maximum number of bytes of entries that will be
+// buffered in memory before a call to the logging service is triggered. See
+// EntryCountThreshold for a discussion of the tradeoffs involved in setting
+// this option.
+// The default is DefaultEntryByteThreshold.
+func EntryByteThreshold(n int) LoggerOption { return entryByteThreshold(n) }
+
+type entryByteThreshold int
+
+func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) }
+
+// EntryByteLimit is the maximum number of bytes of entries that will be sent
+// in a single call to the logging service. This option limits the size of a
+// single RPC payload, to account for network or service issues with large
+// RPCs. If EntryByteLimit is smaller than EntryByteThreshold, the latter has
+// no effect.
+// The default is zero, meaning there is no limit.
+func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) }
+
+type entryByteLimit int
+
+func (e entryByteLimit) set(l *Logger) { l.bundler.BundleByteLimit = int(e) }
+
+// BufferedByteLimit is the maximum number of bytes that the Logger will keep
+// in memory before returning ErrOverflow. This option limits the total memory
+// consumption of the Logger (but note that each Logger has its own, separate
+// limit). It is possible to reach BufferedByteLimit even if it is larger than
+// EntryByteThreshold or EntryByteLimit, because calls triggered by the latter
+// two options may be enqueued (and hence occupying memory) while new log
+// entries are being added.
+// The default is DefaultBufferedByteLimit.
+func BufferedByteLimit(n int) LoggerOption { return bufferedByteLimit(n) }
+
+type bufferedByteLimit int
+
+func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b) }
+
+// Logger returns a Logger that will write entries with the given log ID, such as
+// "syslog". A log ID must be less than 512 characters long and can only
+// include the following characters: upper and lower case alphanumeric
+// characters: [A-Za-z0-9]; and punctuation characters: forward-slash,
+// underscore, hyphen, and period.
+func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
+ r := detectResource()
+ if r == nil {
+ r = globalResource(c.projectID)
+ }
+ l := &Logger{
+ client: c,
+ logName: internal.LogPath(c.parent(), logID),
+ commonResource: r,
+ }
+ // TODO(jba): determine the right context for the bundle handler.
+ ctx := context.TODO()
+ l.bundler = bundler.NewBundler(&logpb.LogEntry{}, func(entries interface{}) {
+ l.writeLogEntries(ctx, entries.([]*logpb.LogEntry))
+ })
+ l.bundler.DelayThreshold = DefaultDelayThreshold
+ l.bundler.BundleCountThreshold = DefaultEntryCountThreshold
+ l.bundler.BundleByteThreshold = DefaultEntryByteThreshold
+ l.bundler.BufferedByteLimit = DefaultBufferedByteLimit
+ for _, opt := range opts {
+ opt.set(l)
+ }
+
+ l.stdLoggers = map[Severity]*log.Logger{}
+ for s := range severityName {
+ l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0)
+ }
+ c.loggers.Add(1)
+ go func() {
+ defer c.loggers.Done()
+ <-c.donec
+ l.bundler.Flush()
+ }()
+ return l
+}
+
+type severityWriter struct {
+ l *Logger
+ s Severity
+}
+
+func (w severityWriter) Write(p []byte) (n int, err error) {
+ w.l.Log(Entry{
+ Severity: w.s,
+ Payload: string(p),
+ })
+ return len(p), nil
+}
+
+// Close closes the client.
+func (c *Client) Close() error {
+ if c.closed {
+ return nil
+ }
+ close(c.donec) // close Logger bundlers
+ c.loggers.Wait() // wait for all bundlers to flush and close
+ // Now there can be no more errors.
+ close(c.errc) // terminate error goroutine
+ // Return only the first error. Since all clients share an underlying connection,
+ // Closes after the first always report a "connection is closing" error.
+ err := c.client.Close()
+ c.closed = true
+ return err
+}
+
+// Severity is the severity of the event described in a log entry. These
+// guideline severity levels are ordered, with numerically smaller levels
+// treated as less severe than numerically larger levels.
+type Severity int
+
+const (
+ // Default means the log entry has no assigned severity level.
+ Default = Severity(logtypepb.LogSeverity_DEFAULT)
+ // Debug means debug or trace information.
+ Debug = Severity(logtypepb.LogSeverity_DEBUG)
+ // Info means routine information, such as ongoing status or performance.
+ Info = Severity(logtypepb.LogSeverity_INFO)
+ // Notice means normal but significant events, such as start up, shut down, or configuration.
+ Notice = Severity(logtypepb.LogSeverity_NOTICE)
+ // Warning means events that might cause problems.
+ Warning = Severity(logtypepb.LogSeverity_WARNING)
+ // Error means events that are likely to cause problems.
+ Error = Severity(logtypepb.LogSeverity_ERROR)
+ // Critical means events that cause more severe problems or brief outages.
+ Critical = Severity(logtypepb.LogSeverity_CRITICAL)
+ // Alert means a person must take an action immediately.
+ Alert = Severity(logtypepb.LogSeverity_ALERT)
+ // Emergency means one or more systems are unusable.
+ Emergency = Severity(logtypepb.LogSeverity_EMERGENCY)
+)
+
+var severityName = map[Severity]string{
+ Default: "Default",
+ Debug: "Debug",
+ Info: "Info",
+ Notice: "Notice",
+ Warning: "Warning",
+ Error: "Error",
+ Critical: "Critical",
+ Alert: "Alert",
+ Emergency: "Emergency",
+}
+
+// String converts a severity level to a string.
+func (v Severity) String() string {
+ // same as proto.EnumName
+ s, ok := severityName[v]
+ if ok {
+ return s
+ }
+ return strconv.Itoa(int(v))
+}
+
+// ParseSeverity returns the Severity whose name equals s, ignoring case. It
+// returns Default if no Severity matches.
+func ParseSeverity(s string) Severity {
+ sl := strings.ToLower(s)
+ for sev, name := range severityName {
+ if strings.ToLower(name) == sl {
+ return sev
+ }
+ }
+ return Default
+}
+
+// Entry is a log entry.
+// See https://cloud.google.com/logging/docs/view/logs_index for more about entries.
+type Entry struct {
+ // Timestamp is the time of the entry. If zero, the current time is used.
+ Timestamp time.Time
+
+ // Severity is the entry's severity level.
+ // The zero value is Default.
+ Severity Severity
+
+ // Payload must be either a string or something that
+ // marshals via the encoding/json package to a JSON object
+ // (and not any other type of JSON value).
+ Payload interface{}
+
+ // Labels optionally specifies key/value labels for the log entry.
+ // The Logger.Log method takes ownership of this map. See Logger.CommonLabels
+ // for more about labels.
+ Labels map[string]string
+
+ // InsertID is a unique ID for the log entry. If you provide this field,
+ // the logging service considers other log entries in the same log with the
+ // same ID as duplicates which can be removed. If omitted, the logging
+ // service will generate a unique ID for this log entry. Note that because
+ // this client retries RPCs automatically, it is possible (though unlikely)
+ // that an Entry without an InsertID will be written more than once.
+ InsertID string
+
+ // HTTPRequest optionally specifies metadata about the HTTP request
+ // associated with this log entry, if applicable. It is optional.
+ HTTPRequest *HTTPRequest
+
+ // Operation optionally provides information about an operation associated
+ // with the log entry, if applicable.
+ Operation *logpb.LogEntryOperation
+
+ // LogName is the full log name, in the form
+ // "projects/{ProjectID}/logs/{LogID}". It is set by the client when
+ // reading entries. It is an error to set it when writing entries.
+ LogName string
+
+ // Resource is the monitored resource associated with the entry. It is set
+ // by the client when reading entries. It is an error to set it when
+ // writing entries.
+ Resource *mrpb.MonitoredResource
+
+ // Trace is the resource name of the trace associated with the log entry,
+ // if any. If it contains a relative resource name, the name is assumed to
+ // be relative to //tracing.googleapis.com.
+ Trace string
+}
+
+// HTTPRequest contains an http.Request as well as additional
+// information about the request and its response.
+type HTTPRequest struct {
+ // Request is the http.Request passed to the handler.
+ Request *http.Request
+
+ // RequestSize is the size of the HTTP request message in bytes, including
+ // the request headers and the request body.
+ RequestSize int64
+
+ // Status is the response code indicating the status of the response.
+ // Examples: 200, 404.
+ Status int
+
+ // ResponseSize is the size of the HTTP response message sent back to the client, in bytes,
+ // including the response headers and the response body.
+ ResponseSize int64
+
+ // Latency is the request processing latency on the server, from the time the request was
+ // received until the response was sent.
+ Latency time.Duration
+
+ // LocalIP is the IP address (IPv4 or IPv6) of the origin server that the request
+ // was sent to.
+ LocalIP string
+
+ // RemoteIP is the IP address (IPv4 or IPv6) of the client that issued the
+ // HTTP request. Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329".
+ RemoteIP string
+
+ // CacheHit reports whether an entity was served from cache (with or without
+ // validation).
+ CacheHit bool
+
+ // CacheValidatedWithOriginServer reports whether the response was
+ // validated with the origin server before being served from cache. This
+ // field is only meaningful if CacheHit is true.
+ CacheValidatedWithOriginServer bool
+}
+
+func fromHTTPRequest(r *HTTPRequest) *logtypepb.HttpRequest {
+ if r == nil {
+ return nil
+ }
+ if r.Request == nil {
+ panic("HTTPRequest must have a non-nil Request")
+ }
+ u := *r.Request.URL
+ u.Fragment = ""
+ pb := &logtypepb.HttpRequest{
+ RequestMethod: r.Request.Method,
+ RequestUrl: u.String(),
+ RequestSize: r.RequestSize,
+ Status: int32(r.Status),
+ ResponseSize: r.ResponseSize,
+ UserAgent: r.Request.UserAgent(),
+ ServerIp: r.LocalIP,
+ RemoteIp: r.RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr?
+ Referer: r.Request.Referer(),
+ CacheHit: r.CacheHit,
+ CacheValidatedWithOriginServer: r.CacheValidatedWithOriginServer,
+ }
+ if r.Latency != 0 {
+ pb.Latency = ptypes.DurationProto(r.Latency)
+ }
+ return pb
+}
+
+// toProtoStruct converts v, which must marshal into a JSON object,
+// into a Google Struct proto.
+func toProtoStruct(v interface{}) (*structpb.Struct, error) {
+ // Fast path: if v is already a *structpb.Struct, nothing to do.
+ if s, ok := v.(*structpb.Struct); ok {
+ return s, nil
+ }
+ // v is a Go struct that supports JSON marshalling. We want a Struct
+ // protobuf. Some day we may have a more direct way to get there, but right
+ // now the only way is to marshal the Go struct to JSON, unmarshal into a
+ // map, and then build the Struct proto from the map.
+ jb, err := json.Marshal(v)
+ if err != nil {
+ return nil, fmt.Errorf("logging: json.Marshal: %v", err)
+ }
+ var m map[string]interface{}
+ err = json.Unmarshal(jb, &m)
+ if err != nil {
+ return nil, fmt.Errorf("logging: json.Unmarshal: %v", err)
+ }
+ return jsonMapToProtoStruct(m), nil
+}
+
+func jsonMapToProtoStruct(m map[string]interface{}) *structpb.Struct {
+ fields := map[string]*structpb.Value{}
+ for k, v := range m {
+ fields[k] = jsonValueToStructValue(v)
+ }
+ return &structpb.Struct{Fields: fields}
+}
+
+func jsonValueToStructValue(v interface{}) *structpb.Value {
+ switch x := v.(type) {
+ case bool:
+ return &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: x}}
+ case float64:
+ return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: x}}
+ case string:
+ return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: x}}
+ case nil:
+ return &structpb.Value{Kind: &structpb.Value_NullValue{}}
+ case map[string]interface{}:
+ return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: jsonMapToProtoStruct(x)}}
+ case []interface{}:
+ var vals []*structpb.Value
+ for _, e := range x {
+ vals = append(vals, jsonValueToStructValue(e))
+ }
+ return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: vals}}}
+ default:
+ panic(fmt.Sprintf("bad type %T for JSON value", v))
+ }
+}
+
+// LogSync logs the Entry synchronously without any buffering. Because LogSync is slow
+// and will block, it is intended primarily for debugging or critical errors.
+// Prefer Log for most uses.
+// TODO(jba): come up with a better name (LogNow?) or eliminate.
+func (l *Logger) LogSync(ctx context.Context, e Entry) error {
+ ent, err := toLogEntry(e)
+ if err != nil {
+ return err
+ }
+ _, err = l.client.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
+ LogName: l.logName,
+ Resource: l.commonResource,
+ Labels: l.commonLabels,
+ Entries: []*logpb.LogEntry{ent},
+ })
+ return err
+}
+
+// Log buffers the Entry for output to the logging service. It never blocks.
+func (l *Logger) Log(e Entry) {
+ ent, err := toLogEntry(e)
+ if err != nil {
+ l.error(err)
+ return
+ }
+ if err := l.bundler.Add(ent, proto.Size(ent)); err != nil {
+ l.error(err)
+ }
+}
+
+// Flush blocks until all currently buffered log entries are sent.
+func (l *Logger) Flush() {
+ l.bundler.Flush()
+}
+
+func (l *Logger) writeLogEntries(ctx context.Context, entries []*logpb.LogEntry) {
+ req := &logpb.WriteLogEntriesRequest{
+ LogName: l.logName,
+ Resource: l.commonResource,
+ Labels: l.commonLabels,
+ Entries: entries,
+ }
+ _, err := l.client.client.WriteLogEntries(ctx, req)
+ if err != nil {
+ l.error(err)
+ }
+}
+
+// error puts the error on the client's error channel
+// without blocking.
+func (l *Logger) error(err error) {
+ select {
+ case l.client.errc <- err:
+ default:
+ }
+}
+
+// StandardLogger returns a *log.Logger for the provided severity.
+//
+// This method is cheap. A single log.Logger is pre-allocated for each
+// severity level in each Logger. Callers may mutate the returned log.Logger
+// (for example by calling SetFlags or SetPrefix).
+func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] }
+
+func trunc32(i int) int32 {
+ if i > math.MaxInt32 {
+ i = math.MaxInt32
+ }
+ return int32(i)
+}
+
+func toLogEntry(e Entry) (*logpb.LogEntry, error) {
+ if e.LogName != "" {
+ return nil, errors.New("logging: Entry.LogName should be not be set when writing")
+ }
+ t := e.Timestamp
+ if t.IsZero() {
+ t = now()
+ }
+ ts, err := ptypes.TimestampProto(t)
+ if err != nil {
+ return nil, err
+ }
+ ent := &logpb.LogEntry{
+ Timestamp: ts,
+ Severity: logtypepb.LogSeverity(e.Severity),
+ InsertId: e.InsertID,
+ HttpRequest: fromHTTPRequest(e.HTTPRequest),
+ Operation: e.Operation,
+ Labels: e.Labels,
+ Trace: e.Trace,
+ }
+
+ switch p := e.Payload.(type) {
+ case string:
+ ent.Payload = &logpb.LogEntry_TextPayload{TextPayload: p}
+ default:
+ s, err := toProtoStruct(p)
+ if err != nil {
+ return nil, err
+ }
+ ent.Payload = &logpb.LogEntry_JsonPayload{JsonPayload: s}
+ }
+ return ent, nil
+}
diff --git a/vendor/cloud.google.com/go/logging/logging_test.go b/vendor/cloud.google.com/go/logging/logging_test.go
new file mode 100644
index 000000000..3bc87e934
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logging_test.go
@@ -0,0 +1,486 @@
+// 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.
+
+// TODO(jba): test that OnError is getting called appropriately.
+
+package logging_test
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ gax "github.com/googleapis/gax-go"
+
+ cinternal "cloud.google.com/go/internal"
+ "cloud.google.com/go/internal/testutil"
+ "cloud.google.com/go/logging"
+ ltesting "cloud.google.com/go/logging/internal/testing"
+ "cloud.google.com/go/logging/logadmin"
+ "golang.org/x/net/context"
+ "golang.org/x/oauth2"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ "google.golang.org/grpc"
+)
+
+const testLogIDPrefix = "GO-LOGGING-CLIENT/TEST-LOG"
+
+var uids = testutil.NewUIDSpace(testLogIDPrefix)
+
+var (
+ client *logging.Client
+ aclient *logadmin.Client
+ testProjectID string
+ testLogID string
+ testFilter string
+ errorc chan error
+ ctx context.Context
+
+ // Adjust the fields of a FullEntry received from the production service
+ // before comparing it with the expected result. We can't correctly
+ // compare certain fields, like times or server-generated IDs.
+ clean func(*logging.Entry)
+
+ // Create a new client with the given project ID.
+ newClients func(ctx context.Context, projectID string) (*logging.Client, *logadmin.Client)
+)
+
+func testNow() time.Time {
+ return time.Unix(1000, 0)
+}
+
+// If true, this test is using the production service, not a fake.
+var integrationTest bool
+
+func TestMain(m *testing.M) {
+ flag.Parse() // needed for testing.Short()
+ ctx = context.Background()
+ testProjectID = testutil.ProjID()
+ errorc = make(chan error, 100)
+ if testProjectID == "" || testing.Short() {
+ integrationTest = false
+ if testProjectID != "" {
+ log.Print("Integration tests skipped in short mode (using fake instead)")
+ }
+ testProjectID = "PROJECT_ID"
+ clean = func(e *logging.Entry) {
+ // Remove the insert ID for consistency with the integration test.
+ e.InsertID = ""
+ }
+
+ addr, err := ltesting.NewServer()
+ if err != nil {
+ log.Fatalf("creating fake server: %v", err)
+ }
+ logging.SetNow(testNow)
+
+ newClients = func(ctx context.Context, projectID string) (*logging.Client, *logadmin.Client) {
+ conn, err := grpc.Dial(addr, grpc.WithInsecure())
+ if err != nil {
+ log.Fatalf("dialing %q: %v", addr, err)
+ }
+ c, err := logging.NewClient(ctx, projectID, option.WithGRPCConn(conn))
+ if err != nil {
+ log.Fatalf("creating client for fake at %q: %v", addr, err)
+ }
+ ac, err := logadmin.NewClient(ctx, projectID, option.WithGRPCConn(conn))
+ if err != nil {
+ log.Fatalf("creating client for fake at %q: %v", addr, err)
+ }
+ return c, ac
+ }
+
+ } else {
+ integrationTest = true
+ clean = func(e *logging.Entry) {
+ // We cannot compare timestamps, so set them to the test time.
+ // Also, remove the insert ID added by the service.
+ e.Timestamp = testNow().UTC()
+ e.InsertID = ""
+ }
+ ts := testutil.TokenSource(ctx, logging.AdminScope)
+ if ts == nil {
+ log.Fatal("The project key must be set. See CONTRIBUTING.md for details")
+ }
+ log.Printf("running integration tests with project %s", testProjectID)
+ newClients = func(ctx context.Context, projectID string) (*logging.Client, *logadmin.Client) {
+ c, err := logging.NewClient(ctx, projectID, option.WithTokenSource(ts))
+ if err != nil {
+ log.Fatalf("creating prod client: %v", err)
+ }
+ ac, err := logadmin.NewClient(ctx, projectID, option.WithTokenSource(ts))
+ if err != nil {
+ log.Fatalf("creating prod client: %v", err)
+ }
+ return c, ac
+ }
+
+ }
+ client, aclient = newClients(ctx, testProjectID)
+ client.OnError = func(e error) { errorc <- e }
+
+ exit := m.Run()
+ client.Close()
+ os.Exit(exit)
+}
+
+func initLogs(ctx context.Context) {
+ testLogID = uids.New()
+ testFilter = fmt.Sprintf(`logName = "projects/%s/logs/%s"`, testProjectID,
+ strings.Replace(testLogID, "/", "%2F", -1))
+}
+
+// Testing of Logger.Log is done in logadmin_test.go, TestEntries.
+
+func TestLogSync(t *testing.T) {
+ initLogs(ctx) // Generate new testLogID
+ ctx := context.Background()
+ lg := client.Logger(testLogID)
+ err := lg.LogSync(ctx, logging.Entry{Payload: "hello"})
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = lg.LogSync(ctx, logging.Entry{Payload: "goodbye"})
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Allow overriding the MonitoredResource.
+ err = lg.LogSync(ctx, logging.Entry{Payload: "mr", Resource: &mrpb.MonitoredResource{Type: "global"}})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := []*logging.Entry{
+ entryForTesting("hello"),
+ entryForTesting("goodbye"),
+ entryForTesting("mr"),
+ }
+ var got []*logging.Entry
+ ok := waitFor(func() bool {
+ got, err = allTestLogEntries(ctx)
+ if err != nil {
+ t.Log("fetching log entries: ", err)
+ return false
+ }
+ return len(got) == len(want)
+ })
+ if !ok {
+ t.Fatalf("timed out; got: %d, want: %d\n", len(got), len(want))
+ }
+ if msg, ok := compareEntries(got, want); !ok {
+ t.Error(msg)
+ }
+}
+
+func TestLogAndEntries(t *testing.T) {
+ initLogs(ctx) // Generate new testLogID
+ ctx := context.Background()
+ payloads := []string{"p1", "p2", "p3", "p4", "p5"}
+ lg := client.Logger(testLogID)
+ for _, p := range payloads {
+ // Use the insert ID to guarantee iteration order.
+ lg.Log(logging.Entry{Payload: p, InsertID: p})
+ }
+ lg.Flush()
+ var want []*logging.Entry
+ for _, p := range payloads {
+ want = append(want, entryForTesting(p))
+ }
+ var got []*logging.Entry
+ ok := waitFor(func() bool {
+ var err error
+ got, err = allTestLogEntries(ctx)
+ if err != nil {
+ t.Log("fetching log entries: ", err)
+ return false
+ }
+ return len(got) == len(want)
+ })
+ if !ok {
+ t.Fatalf("timed out; got: %d, want: %d\n", len(got), len(want))
+ }
+ if msg, ok := compareEntries(got, want); !ok {
+ t.Error(msg)
+ }
+}
+
+// compareEntries compares most fields list of Entries against expected. compareEntries does not compare:
+// - HTTPRequest
+// - Operation
+// - Resource
+func compareEntries(got, want []*logging.Entry) (string, bool) {
+ if len(got) != len(want) {
+ return fmt.Sprintf("got %d entries, want %d", len(got), len(want)), false
+ }
+ for i := range got {
+ if !compareEntry(got[i], want[i]) {
+ return fmt.Sprintf("#%d:\ngot %+v\nwant %+v", i, got[i], want[i]), false
+ }
+ }
+ return "", true
+}
+
+func compareEntry(got, want *logging.Entry) bool {
+ if got.Timestamp.Unix() != want.Timestamp.Unix() {
+ return false
+ }
+
+ if got.Severity != want.Severity {
+ return false
+ }
+
+ if !ltesting.PayloadEqual(got.Payload, want.Payload) {
+ return false
+ }
+ if !reflect.DeepEqual(got.Labels, want.Labels) {
+ return false
+ }
+
+ if got.InsertID != want.InsertID {
+ return false
+ }
+
+ if got.LogName != want.LogName {
+ return false
+ }
+
+ return true
+}
+
+func entryForTesting(payload interface{}) *logging.Entry {
+ return &logging.Entry{
+ Timestamp: testNow().UTC(),
+ Payload: payload,
+ LogName: "projects/" + testProjectID + "/logs/" + testLogID,
+ Resource: &mrpb.MonitoredResource{Type: "global", Labels: map[string]string{"project_id": testProjectID}},
+ }
+}
+
+func countLogEntries(ctx context.Context, filter string) int {
+ it := aclient.Entries(ctx, logadmin.Filter(filter))
+ n := 0
+ for {
+ _, err := it.Next()
+ if err == iterator.Done {
+ return n
+ }
+ if err != nil {
+ log.Fatalf("counting log entries: %v", err)
+ }
+ n++
+ }
+}
+
+func allTestLogEntries(ctx context.Context) ([]*logging.Entry, error) {
+ var es []*logging.Entry
+ it := aclient.Entries(ctx, logadmin.Filter(testFilter))
+ for {
+ e, err := cleanNext(it)
+ switch err {
+ case nil:
+ es = append(es, e)
+ case iterator.Done:
+ return es, nil
+ default:
+ return nil, err
+ }
+ }
+}
+
+func cleanNext(it *logadmin.EntryIterator) (*logging.Entry, error) {
+ e, err := it.Next()
+ if err != nil {
+ return nil, err
+ }
+ clean(e)
+ return e, nil
+}
+
+func TestStandardLogger(t *testing.T) {
+ initLogs(ctx) // Generate new testLogID
+ ctx := context.Background()
+ lg := client.Logger(testLogID)
+ slg := lg.StandardLogger(logging.Info)
+
+ if slg != lg.StandardLogger(logging.Info) {
+ t.Error("There should be only one standard logger at each severity.")
+ }
+ if slg == lg.StandardLogger(logging.Debug) {
+ t.Error("There should be a different standard logger for each severity.")
+ }
+
+ slg.Print("info")
+ lg.Flush()
+ var got []*logging.Entry
+ ok := waitFor(func() bool {
+ var err error
+ got, err = allTestLogEntries(ctx)
+ if err != nil {
+ t.Log("fetching log entries: ", err)
+ return false
+ }
+ return len(got) == 1
+ })
+ if !ok {
+ t.Fatalf("timed out; got: %d, want: %d\n", len(got), 1)
+ }
+ if len(got) != 1 {
+ t.Fatalf("expected non-nil request with one entry; got:\n%+v", got)
+ }
+ if got, want := got[0].Payload.(string), "info\n"; got != want {
+ t.Errorf("payload: got %q, want %q", got, want)
+ }
+ if got, want := logging.Severity(got[0].Severity), logging.Info; got != want {
+ t.Errorf("severity: got %s, want %s", got, want)
+ }
+}
+
+func TestSeverity(t *testing.T) {
+ if got, want := logging.Info.String(), "Info"; got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+ if got, want := logging.Severity(-99).String(), "-99"; got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
+
+func TestParseSeverity(t *testing.T) {
+ for _, test := range []struct {
+ in string
+ want logging.Severity
+ }{
+ {"", logging.Default},
+ {"whatever", logging.Default},
+ {"Default", logging.Default},
+ {"ERROR", logging.Error},
+ {"Error", logging.Error},
+ {"error", logging.Error},
+ } {
+ got := logging.ParseSeverity(test.in)
+ if got != test.want {
+ t.Errorf("%q: got %s, want %s\n", test.in, got, test.want)
+ }
+ }
+}
+
+func TestErrors(t *testing.T) {
+ initLogs(ctx) // Generate new testLogID
+ // Drain errors already seen.
+loop:
+ for {
+ select {
+ case <-errorc:
+ default:
+ break loop
+ }
+ }
+ // Try to log something that can't be JSON-marshalled.
+ lg := client.Logger(testLogID)
+ lg.Log(logging.Entry{Payload: func() {}})
+ // Expect an error.
+ select {
+ case <-errorc: // pass
+ case <-time.After(100 * time.Millisecond):
+ t.Fatal("expected an error but timed out")
+ }
+}
+
+type badTokenSource struct{}
+
+func (badTokenSource) Token() (*oauth2.Token, error) {
+ return &oauth2.Token{}, nil
+}
+
+func TestPing(t *testing.T) {
+ // Ping twice, in case the service's InsertID logic messes with the error code.
+ ctx := context.Background()
+ // The global client should be valid.
+ if err := client.Ping(ctx); err != nil {
+ t.Errorf("project %s: got %v, expected nil", testProjectID, err)
+ }
+ if err := client.Ping(ctx); err != nil {
+ t.Errorf("project %s, #2: got %v, expected nil", testProjectID, err)
+ }
+ // nonexistent project
+ c, _ := newClients(ctx, testProjectID+"-BAD")
+ if err := c.Ping(ctx); err == nil {
+ t.Errorf("nonexistent project: want error pinging logging api, got nil")
+ }
+ if err := c.Ping(ctx); err == nil {
+ t.Errorf("nonexistent project, #2: want error pinging logging api, got nil")
+ }
+
+ // Bad creds. We cannot test this with the fake, since it doesn't do auth.
+ if integrationTest {
+ c, err := logging.NewClient(ctx, testProjectID, option.WithTokenSource(badTokenSource{}))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.Ping(ctx); err == nil {
+ t.Errorf("bad creds: want error pinging logging api, got nil")
+ }
+ if err := c.Ping(ctx); err == nil {
+ t.Errorf("bad creds, #2: want error pinging logging api, got nil")
+ }
+ if err := c.Close(); err != nil {
+ t.Fatalf("error closing client: %v", err)
+ }
+ }
+}
+
+func TestLogsAndDelete(t *testing.T) {
+ // This function tests both the Logs and DeleteLog methods. We only try to
+ // delete those logs that we can observe and that were generated by this
+ // test. This may not include the logs generated from the current test run,
+ // because the logging service is only eventually consistent. It's
+ // therefore possible that on some runs, this test will do nothing.
+ ctx := context.Background()
+ it := aclient.Logs(ctx)
+ nDeleted := 0
+ for {
+ logID, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if strings.HasPrefix(logID, testLogIDPrefix) {
+ if err := aclient.DeleteLog(ctx, logID); err != nil {
+ t.Fatalf("deleting %q: %v", logID, err)
+ }
+ nDeleted++
+ }
+ }
+ t.Logf("deleted %d logs", nDeleted)
+}
+
+// waitFor calls f repeatedly with exponential backoff, blocking until it returns true.
+// It returns false after a while (if it times out).
+func waitFor(f func() bool) bool {
+ // TODO(shadams): Find a better way to deflake these tests.
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
+ defer cancel()
+ err := cinternal.Retry(ctx,
+ gax.Backoff{Initial: time.Second, Multiplier: 2},
+ func() (bool, error) { return f(), nil })
+ return err == nil
+}
diff --git a/vendor/cloud.google.com/go/logging/logging_unexported_test.go b/vendor/cloud.google.com/go/logging/logging_unexported_test.go
new file mode 100644
index 000000000..cd4b6ebce
--- /dev/null
+++ b/vendor/cloud.google.com/go/logging/logging_unexported_test.go
@@ -0,0 +1,228 @@
+// 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.
+
+// Tests that require access to unexported names of the logging package.
+
+package logging
+
+import (
+ "net/http"
+ "net/url"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ durpb "github.com/golang/protobuf/ptypes/duration"
+ structpb "github.com/golang/protobuf/ptypes/struct"
+ "google.golang.org/api/support/bundler"
+ mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
+ logtypepb "google.golang.org/genproto/googleapis/logging/type"
+)
+
+func TestLoggerCreation(t *testing.T) {
+ const logID = "testing"
+ c := &Client{projectID: "PROJECT_ID"}
+ customResource := &mrpb.MonitoredResource{
+ Type: "global",
+ Labels: map[string]string{
+ "project_id": "ANOTHER_PROJECT",
+ },
+ }
+ defaultBundler := &bundler.Bundler{
+ DelayThreshold: DefaultDelayThreshold,
+ BundleCountThreshold: DefaultEntryCountThreshold,
+ BundleByteThreshold: DefaultEntryByteThreshold,
+ BundleByteLimit: 0,
+ BufferedByteLimit: DefaultBufferedByteLimit,
+ }
+ for _, test := range []struct {
+ options []LoggerOption
+ wantLogger *Logger
+ defaultResource bool
+ wantBundler *bundler.Bundler
+ }{
+ {
+ options: nil,
+ wantLogger: &Logger{},
+ defaultResource: true,
+ wantBundler: defaultBundler,
+ },
+ {
+ options: []LoggerOption{
+ CommonResource(nil),
+ CommonLabels(map[string]string{"a": "1"}),
+ },
+ wantLogger: &Logger{
+ commonResource: nil,
+ commonLabels: map[string]string{"a": "1"},
+ },
+ wantBundler: defaultBundler,
+ },
+ {
+ options: []LoggerOption{CommonResource(customResource)},
+ wantLogger: &Logger{commonResource: customResource},
+ wantBundler: defaultBundler,
+ },
+ {
+ options: []LoggerOption{
+ DelayThreshold(time.Minute),
+ EntryCountThreshold(99),
+ EntryByteThreshold(17),
+ EntryByteLimit(18),
+ BufferedByteLimit(19),
+ },
+ wantLogger: &Logger{},
+ defaultResource: true,
+ wantBundler: &bundler.Bundler{
+ DelayThreshold: time.Minute,
+ BundleCountThreshold: 99,
+ BundleByteThreshold: 17,
+ BundleByteLimit: 18,
+ BufferedByteLimit: 19,
+ },
+ },
+ } {
+ gotLogger := c.Logger(logID, test.options...)
+ if got, want := gotLogger.commonResource, test.wantLogger.commonResource; !test.defaultResource && !proto.Equal(got, want) {
+ t.Errorf("%v: resource: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.commonLabels, test.wantLogger.commonLabels; !reflect.DeepEqual(got, want) {
+ t.Errorf("%v: commonLabels: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.bundler.DelayThreshold, test.wantBundler.DelayThreshold; got != want {
+ t.Errorf("%v: DelayThreshold: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.bundler.BundleCountThreshold, test.wantBundler.BundleCountThreshold; got != want {
+ t.Errorf("%v: BundleCountThreshold: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.bundler.BundleByteThreshold, test.wantBundler.BundleByteThreshold; got != want {
+ t.Errorf("%v: BundleByteThreshold: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.bundler.BundleByteLimit, test.wantBundler.BundleByteLimit; got != want {
+ t.Errorf("%v: BundleByteLimit: got %v, want %v", test.options, got, want)
+ }
+ if got, want := gotLogger.bundler.BufferedByteLimit, test.wantBundler.BufferedByteLimit; got != want {
+ t.Errorf("%v: BufferedByteLimit: got %v, want %v", test.options, got, want)
+ }
+ }
+}
+
+func TestToProtoStruct(t *testing.T) {
+ v := struct {
+ Foo string `json:"foo"`
+ Bar int `json:"bar,omitempty"`
+ Baz []float64 `json:"baz"`
+ Moo map[string]interface{} `json:"moo"`
+ }{
+ Foo: "foovalue",
+ Baz: []float64{1.1},
+ Moo: map[string]interface{}{
+ "a": 1,
+ "b": "two",
+ "c": true,
+ },
+ }
+
+ got, err := toProtoStruct(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := &structpb.Struct{
+ Fields: map[string]*structpb.Value{
+ "foo": {Kind: &structpb.Value_StringValue{StringValue: v.Foo}},
+ "baz": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: []*structpb.Value{
+ {Kind: &structpb.Value_NumberValue{NumberValue: 1.1}},
+ }}}},
+ "moo": {Kind: &structpb.Value_StructValue{
+ StructValue: &structpb.Struct{
+ Fields: map[string]*structpb.Value{
+ "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}},
+ "b": {Kind: &structpb.Value_StringValue{StringValue: "two"}},
+ "c": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
+ },
+ },
+ }},
+ },
+ }
+ if !proto.Equal(got, want) {
+ t.Errorf("got %+v\nwant %+v", got, want)
+ }
+
+ // Non-structs should fail to convert.
+ for v := range []interface{}{3, "foo", []int{1, 2, 3}} {
+ _, err := toProtoStruct(v)
+ if err == nil {
+ t.Errorf("%v: got nil, want error", v)
+ }
+ }
+
+ // Test fast path.
+ got, err = toProtoStruct(want)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got != want {
+ t.Error("got and want should be identical, but are not")
+ }
+}
+
+func TestFromHTTPRequest(t *testing.T) {
+ const testURL = "http:://example.com/path?q=1"
+ u, err := url.Parse(testURL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req := &HTTPRequest{
+ Request: &http.Request{
+ Method: "GET",
+ URL: u,
+ Header: map[string][]string{
+ "User-Agent": []string{"user-agent"},
+ "Referer": []string{"referer"},
+ },
+ },
+ RequestSize: 100,
+ Status: 200,
+ ResponseSize: 25,
+ Latency: 100 * time.Second,
+ LocalIP: "127.0.0.1",
+ RemoteIP: "10.0.1.1",
+ CacheHit: true,
+ CacheValidatedWithOriginServer: true,
+ }
+ got := fromHTTPRequest(req)
+ want := &logtypepb.HttpRequest{
+ RequestMethod: "GET",
+ RequestUrl: testURL,
+ RequestSize: 100,
+ Status: 200,
+ ResponseSize: 25,
+ Latency: &durpb.Duration{Seconds: 100},
+ UserAgent: "user-agent",
+ ServerIp: "127.0.0.1",
+ RemoteIp: "10.0.1.1",
+ Referer: "referer",
+ CacheHit: true,
+ CacheValidatedWithOriginServer: true,
+ }
+ if !proto.Equal(got, want) {
+ t.Errorf("got %+v\nwant %+v", got, want)
+ }
+}
+
+// Used by the tests in logging_test.
+func SetNow(f func() time.Time) {
+ now = f
+}