func (c *Client) Close() error {
	if c.closed {
		return nil
	}
	close(c.donec)    
	c.loggers.Wait()  
	close(c.errc)  
	err := c.extractErrorInfo()
	err2 := c.client.Close()
	if err == nil {
		err = err2
	}
	c.closed = true
	return err
}
Close waits for all opened loggers to be flushed and closes the client.
package logging
import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"
	"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"
	"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 (
	ReadScope = "https://www.googleapis.com/auth/logging.read"
	WriteScope = "https://www.googleapis.com/auth/logging.write"
	AdminScope = "https://www.googleapis.com/auth/logging.admin"
)
const (
	defaultErrorCapacity = 10
	DefaultDelayThreshold = time.Second
	DefaultEntryCountThreshold = 1000
	DefaultEntryByteThreshold = 1 << 20  
	DefaultBufferedByteLimit = 1 << 30  
	defaultWriteTimeout = 10 * time.Minute
)
var now = time.Now
var ErrOverflow = bundler.ErrOverflow
var ErrOversizedEntry = bundler.ErrOversizedItem
type Client struct {
	client  *vkit.Client    
	parent  string          
	errc    chan error      
	donec   chan struct{}   
	loggers sync.WaitGroup  
	closed  bool
	mu      sync.Mutex
	nErrs   int    
	lastErr error  
	OnError func(err error)
}
func NewClient(ctx context.Context, parent string, opts ...option.ClientOption) (*Client, error) {
	if !strings.ContainsRune(parent, '/') {
		parent = "projects/" + parent
	}
	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,
		parent:  parent,
		errc:    make(chan error, defaultErrorCapacity),  
		donec:   make(chan struct{}),
		OnError: func(e error) { log.Printf("logging client: %v", e) },
	}
	go func() {
		for err := range client.errc {
			if fn := client.OnError; fn != nil {
				fn(err)
			} else {
				log.Printf("logging (parent %q): %v", parent, err)
			}
		}
	}()
	return client, nil
}
var unixZeroTimestamp *tspb.Timestamp
func init() {
	var err error
	unixZeroTimestamp, err = ptypes.TimestampProto(time.Unix(0, 0))
	if err != nil {
		panic(err)
	}
}
func (c *Client) Ping(ctx context.Context) error {
	ent := &logpb.LogEntry{
		Payload:   &logpb.LogEntry_TextPayload{TextPayload: "ping"},
		Timestamp: unixZeroTimestamp,  
		InsertId:  "ping",             
	}
	_, err := c.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
		LogName:  internal.LogPath(c.parent, "ping"),
		Resource: monitoredResource(c.parent),
		Entries:  []*logpb.LogEntry{ent},
	})
	return err
}
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
}
type Logger struct {
	client     *Client
	logName    string  
	stdLoggers map[Severity]*log.Logger
	bundler    *bundler.Bundler
	commonResource *mrpb.MonitoredResource
	commonLabels   map[string]string
	ctxFunc        func() (context.Context, func())
}
type LoggerOption interface {
	set(*Logger)
}
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
		}
		name, err := metadata.InstanceName()
		if err != nil {
			return
		}
		detectedResource.pb = &mrpb.MonitoredResource{
			Type: "gce_instance",
			Labels: map[string]string{
				"project_id":    projectID,
				"instance_id":   id,
				"instance_name": name,
				"zone":          zone,
			},
		}
	})
	return detectedResource.pb
}
var resourceInfo = map[string]struct{ rtype, label string }{
	"organizations":   {"organization", "organization_id"},
	"folders":         {"folder", "folder_id"},
	"projects":        {"project", "project_id"},
	"billingAccounts": {"billing_account", "account_id"},
}
func monitoredResource(parent string) *mrpb.MonitoredResource {
	parts := strings.SplitN(parent, "/", 2)
	if len(parts) != 2 {
		return globalResource(parent)
	}
	info, ok := resourceInfo[parts[0]]
	if !ok {
		return globalResource(parts[1])
	}
	return &mrpb.MonitoredResource{
		Type:   info.rtype,
		Labels: map[string]string{info.label: parts[1]},
	}
}
func globalResource(projectID string) *mrpb.MonitoredResource {
	return &mrpb.MonitoredResource{
		Type: "global",
		Labels: map[string]string{
			"project_id": projectID,
		},
	}
}
func CommonLabels(m map[string]string) LoggerOption { return commonLabels(m) }
type commonLabels map[string]string
func (c commonLabels) set(l *Logger) { l.commonLabels = c }
func ConcurrentWriteLimit(n int) LoggerOption { return concurrentWriteLimit(n) }
type concurrentWriteLimit int
func (c concurrentWriteLimit) set(l *Logger) { l.bundler.HandlerLimit = int(c) }
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) }
func EntryCountThreshold(n int) LoggerOption { return entryCountThreshold(n) }
type entryCountThreshold int
func (e entryCountThreshold) set(l *Logger) { l.bundler.BundleCountThreshold = int(e) }
func EntryByteThreshold(n int) LoggerOption { return entryByteThreshold(n) }
type entryByteThreshold int
func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) }
func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) }
type entryByteLimit int
func (e entryByteLimit) set(l *Logger) { l.bundler.BundleByteLimit = int(e) }
func BufferedByteLimit(n int) LoggerOption { return bufferedByteLimit(n) }
type bufferedByteLimit int
func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b) }
func ContextFunc(f func() (ctx context.Context, afterCall func())) LoggerOption {
	return contextFunc(f)
}
type contextFunc func() (ctx context.Context, afterCall func())
func (c contextFunc) set(l *Logger) { l.ctxFunc = c }
func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
	r := detectResource()
	if r == nil {
		r = monitoredResource(c.parent)
	}
	l := &Logger{
		client:         c,
		logName:        internal.LogPath(c.parent, logID),
		commonResource: r,
		ctxFunc:        func() (context.Context, func()) { return context.Background(), nil },
	}
	l.bundler = bundler.NewBundler(&logpb.LogEntry{}, func(entries interface{}) {
		l.writeLogEntries(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
}