mirror of
https://github.com/restic/restic.git
synced 2025-08-23 16:17:53 +00:00
Vendor dependencies for GCS
This commit is contained in:
11
vendor/cloud.google.com/go/logging/apiv2/README.md
generated
vendored
Normal file
11
vendor/cloud.google.com/go/logging/apiv2/README.md
generated
vendored
Normal file
@@ -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.
|
||||
|
||||
|
66
vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go
generated
vendored
Normal file
66
vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go
generated
vendored
Normal file
@@ -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 = LogPath(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)
|
||||
}
|
||||
}
|
304
vendor/cloud.google.com/go/logging/apiv2/config_client.go
generated
vendored
Normal file
304
vendor/cloud.google.com/go/logging/apiv2/config_client.go
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
// 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.Internal,
|
||||
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
|
||||
}
|
128
vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go
generated
vendored
Normal file
128
vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
// 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"
|
||||
"google.golang.org/api/iterator"
|
||||
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 == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// 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.
|
||||
}
|
||||
}
|
48
vendor/cloud.google.com/go/logging/apiv2/doc.go
generated
vendored
Normal file
48
vendor/cloud.google.com/go/logging/apiv2/doc.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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
|
||||
// Stackdriver 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)
|
||||
}
|
||||
|
||||
// DefaultAuthScopes reports the authentication scopes required
|
||||
// by this package.
|
||||
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",
|
||||
}
|
||||
}
|
434
vendor/cloud.google.com/go/logging/apiv2/logging_client.go
generated
vendored
Normal file
434
vendor/cloud.google.com/go/logging/apiv2/logging_client.go
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
// 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.Internal,
|
||||
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.Internal,
|
||||
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...)}
|
||||
}
|
||||
|
||||
// ProjectPath returns the path for the project resource.
|
||||
func ProjectPath(project string) string {
|
||||
path, err := loggingProjectPathTemplate.Render(map[string]string{
|
||||
"project": project,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// LogPath returns the path for the log resource.
|
||||
func LogPath(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
|
||||
}
|
140
vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go
generated
vendored
Normal file
140
vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
// 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"
|
||||
"google.golang.org/api/iterator"
|
||||
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 == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// 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 == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// 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 == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// TODO: Use resp.
|
||||
_ = resp
|
||||
}
|
||||
}
|
291
vendor/cloud.google.com/go/logging/apiv2/metrics_client.go
generated
vendored
Normal file
291
vendor/cloud.google.com/go/logging/apiv2/metrics_client.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
// 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.Internal,
|
||||
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
|
||||
}
|
128
vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go
generated
vendored
Normal file
128
vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
// 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"
|
||||
"google.golang.org/api/iterator"
|
||||
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 == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// 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.
|
||||
}
|
||||
}
|
1279
vendor/cloud.google.com/go/logging/apiv2/mock_test.go
generated
vendored
Normal file
1279
vendor/cloud.google.com/go/logging/apiv2/mock_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
90
vendor/cloud.google.com/go/logging/doc.go
generated
vendored
Normal file
90
vendor/cloud.google.com/go/logging/doc.go
generated
vendored
Normal file
@@ -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"
|
136
vendor/cloud.google.com/go/logging/examples_test.go
generated
vendored
Normal file
136
vendor/cloud.google.com/go/logging/examples_test.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
|
||||
// Although Logger.Flush and Client.Close both return errors, they don't tell you
|
||||
// whether the errors were frequent or significant. For most programs, it doesn't
|
||||
// matter if there were a few errors while writing logs, although if those few errors
|
||||
// indicated a bug in your program, you might want to know about them. The best way
|
||||
// to handle errors is by setting the OnError function. If it runs quickly, it will
|
||||
// see every error generated during logging.
|
||||
func ExampleNewClient_errorFunc() {
|
||||
ctx := context.Background()
|
||||
client, err := logging.NewClient(ctx, "my-project")
|
||||
if err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
// Print all errors to stdout, and count them. Multiple calls to the OnError
|
||||
// function never happen concurrently, so there is no need for locking nErrs,
|
||||
// provided you don't read it until after the logging client is closed.
|
||||
var nErrs int
|
||||
client.OnError = func(e error) {
|
||||
fmt.Fprintf(os.Stdout, "logging: %v", e)
|
||||
nErrs++
|
||||
}
|
||||
// Use client to manage logs, metrics and sinks.
|
||||
// Close the client when finished.
|
||||
if err := client.Close(); err != nil {
|
||||
// TODO: Handle error.
|
||||
}
|
||||
fmt.Printf("saw %d errors\n", nErrs)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
39
vendor/cloud.google.com/go/logging/internal/common.go
generated
vendored
Normal file
39
vendor/cloud.google.com/go/logging/internal/common.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
42
vendor/cloud.google.com/go/logging/internal/testing/equal.go
generated
vendored
Normal file
42
vendor/cloud.google.com/go/logging/internal/testing/equal.go
generated
vendored
Normal file
@@ -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))
|
||||
}
|
||||
}
|
418
vendor/cloud.google.com/go/logging/internal/testing/fake.go
generated
vendored
Normal file
418
vendor/cloud.google.com/go/logging/internal/testing/fake.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
122
vendor/cloud.google.com/go/logging/internal/testing/fake_test.go
generated
vendored
Normal file
122
vendor/cloud.google.com/go/logging/internal/testing/fake_test.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
66
vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go
generated
vendored
Normal file
66
vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
52
vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go
generated
vendored
Normal file
52
vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
92
vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go
generated
vendored
Normal file
92
vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
52
vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go
generated
vendored
Normal file
52
vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
52
vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go
generated
vendored
Normal file
52
vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
||||
}
|
161
vendor/cloud.google.com/go/logging/logadmin/examples_test.go
generated
vendored
Normal file
161
vendor/cloud.google.com/go/logging/logadmin/examples_test.go
generated
vendored
Normal file
@@ -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)
|
||||
}
|
402
vendor/cloud.google.com/go/logging/logadmin/logadmin.go
generated
vendored
Normal file
402
vendor/cloud.google.com/go/logging/logadmin/logadmin.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
265
vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go
generated
vendored
Normal file
265
vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
// 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"
|
||||
"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)
|
||||
}
|
||||
if diff := testutil.Diff(got, want, testutil.IgnoreUnexported(http.Request{})); diff != "" {
|
||||
t.Errorf("FullEntry:\n%s", diff)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
154
vendor/cloud.google.com/go/logging/logadmin/metrics.go
generated
vendored
Normal file
154
vendor/cloud.google.com/go/logging/logadmin/metrics.go
generated
vendored
Normal file
@@ -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,
|
||||
}
|
||||
}
|
154
vendor/cloud.google.com/go/logging/logadmin/metrics_test.go
generated
vendored
Normal file
154
vendor/cloud.google.com/go/logging/logadmin/metrics_test.go
generated
vendored
Normal file
@@ -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 (
|
||||
"log"
|
||||
"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; !testutil.Equal(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; !testutil.Equal(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; !testutil.Equal(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 !testutil.Equal(got, want) {
|
||||
t.Errorf("got %+v, want %+v", got, want)
|
||||
}
|
||||
}
|
74
vendor/cloud.google.com/go/logging/logadmin/resources.go
generated
vendored
Normal file
74
vendor/cloud.google.com/go/logging/logadmin/resources.go
generated
vendored
Normal file
@@ -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
|
||||
})
|
||||
}
|
46
vendor/cloud.google.com/go/logging/logadmin/resources_test.go
generated
vendored
Normal file
46
vendor/cloud.google.com/go/logging/logadmin/resources_test.go
generated
vendored
Normal file
@@ -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.
|
||||
}
|
169
vendor/cloud.google.com/go/logging/logadmin/sinks.go
generated
vendored
Normal file
169
vendor/cloud.google.com/go/logging/logadmin/sinks.go
generated
vendored
Normal file
@@ -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,
|
||||
}
|
||||
}
|
225
vendor/cloud.google.com/go/logging/logadmin/sinks_test.go
generated
vendored
Normal file
225
vendor/cloud.google.com/go/logging/logadmin/sinks_test.go
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
// 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"
|
||||
"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; !testutil.Equal(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; !testutil.Equal(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; !testutil.Equal(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; !testutil.Equal(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; !testutil.Equal(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 !testutil.Equal(got, want) {
|
||||
t.Errorf("got %+v, want %+v", got, want)
|
||||
}
|
||||
}
|
767
vendor/cloud.google.com/go/logging/logging.go
generated
vendored
Normal file
767
vendor/cloud.google.com/go/logging/logging.go
generated
vendored
Normal file
@@ -0,0 +1,767 @@
|
||||
// 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
|
||||
|
||||
mu sync.Mutex
|
||||
nErrs int // number of errors we saw
|
||||
lastErr error // last error we saw
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// error puts the error on the client's error channel
|
||||
// without blocking, and records summary error info.
|
||||
func (c *Client) error(err error) {
|
||||
select {
|
||||
case c.errc <- err:
|
||||
default:
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.lastErr = err
|
||||
c.nErrs++
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *Client) extractErrorInfo() error {
|
||||
var err error
|
||||
c.mu.Lock()
|
||||
if c.lastErr != nil {
|
||||
err = fmt.Errorf("saw %d errors; last: %v", c.nErrs, c.lastErr)
|
||||
c.nErrs = 0
|
||||
c.lastErr = nil
|
||||
}
|
||||
c.mu.Unlock()
|
||||
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 waits for all opened loggers to be flushed and 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
|
||||
// Prefer logging errors to close errors.
|
||||
err := c.extractErrorInfo()
|
||||
err2 := c.client.Close()
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
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.client.error(err)
|
||||
return
|
||||
}
|
||||
if err := l.bundler.Add(ent, proto.Size(ent)); err != nil {
|
||||
l.client.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Flush blocks until all currently buffered log entries are sent.
|
||||
//
|
||||
// If any errors occurred since the last call to Flush from any Logger, or the
|
||||
// creation of the client if this is the first call, then Flush returns a non-nil
|
||||
// error with summary information about the errors. This information is unlikely to
|
||||
// be actionable. For more accurate error reporting, set Client.OnError.
|
||||
func (l *Logger) Flush() error {
|
||||
l.bundler.Flush()
|
||||
return l.client.extractErrorInfo()
|
||||
}
|
||||
|
||||
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.client.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
484
vendor/cloud.google.com/go/logging/logging_test.go
generated
vendored
Normal file
484
vendor/cloud.google.com/go/logging/logging_test.go
generated
vendored
Normal file
@@ -0,0 +1,484 @@
|
||||
// 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"
|
||||
"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 !testutil.Equal(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 from Flush.
|
||||
err := lg.Flush()
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
229
vendor/cloud.google.com/go/logging/logging_unexported_test.go
generated
vendored
Normal file
229
vendor/cloud.google.com/go/logging/logging_unexported_test.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
// 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"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/internal/testutil"
|
||||
|
||||
"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; !testutil.Equal(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
|
||||
}
|
Reference in New Issue
Block a user