Fetch the repository succeeded.
This action will force synchronization from GoLibs/google-cloud-go, which will overwrite any changes that you have made since you forked the repository, and can not be recovered!!!
Synchronous operation will process in the background and will refresh the page when finishing processing. Please be patient.
// 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"
vkit "cloud.google.com/go/logging/apiv2"
"cloud.google.com/go/logging/internal"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
structpb "github.com/golang/protobuf/ptypes/struct"
tspb "github.com/golang/protobuf/ptypes/timestamp"
"golang.org/x/net/context"
"google.golang.org/api/option"
"google.golang.org/api/support/bundler"
mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
logtypepb "google.golang.org/genproto/googleapis/logging/type"
logpb "google.golang.org/genproto/googleapis/logging/v2"
)
const (
// Scope for reading from the logging service.
ReadScope = "https://www.googleapis.com/auth/logging.read"
// Scope for writing to the logging service.
WriteScope = "https://www.googleapis.com/auth/logging.write"
// Scope for administrative actions on the logging service.
AdminScope = "https://www.googleapis.com/auth/logging.admin"
)
const (
// defaultErrorCapacity is the capacity of the channel used to deliver
// errors to the OnError function.
defaultErrorCapacity = 10
// DefaultDelayThreshold is the default value for the DelayThreshold LoggerOption.
DefaultDelayThreshold = time.Second
// DefaultEntryCountThreshold is the default value for the EntryCountThreshold LoggerOption.
DefaultEntryCountThreshold = 1000
// DefaultEntryByteThreshold is the default value for the EntryByteThreshold LoggerOption.
DefaultEntryByteThreshold = 1 << 20 // 1MiB
// DefaultBufferedByteLimit is the default value for the BufferedByteLimit LoggerOption.
DefaultBufferedByteLimit = 1 << 30 // 1GiB
)
// For testing:
var now = time.Now
// ErrOverflow signals that the number of buffered entries for a Logger
// exceeds its BufferLimit.
var ErrOverflow = errors.New("logging: log entry overflowed buffer limits")
// Client is a Logging client. A Client is associated with a single Cloud project.
type Client struct {
client *vkit.Client // client for the logging service
projectID string
errc chan error // should be buffered to minimize dropped errors
donec chan struct{} // closed on Client.Close to close Logger bundlers
loggers sync.WaitGroup // so we can wait for loggers to close
closed bool
// OnError is called when an error occurs in a call to Log or Flush. The
// error may be due to an invalid Entry, an overflow because BufferLimit
// was reached (in which case the error will be ErrOverflow) or an error
// communicating with the logging service. OnError is called with errors
// from all Loggers. It is never called concurrently. OnError is expected
// to return quickly; if errors occur while OnError is running, some may
// not be reported. The default behavior is to call log.Printf.
//
// This field should be set only once, before any method of Client is called.
OnError func(err error)
}
// NewClient returns a new logging client associated with the provided project ID.
//
// By default NewClient uses WriteScope. To use a different scope, call
// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes).
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
// Check for '/' in project ID to reserve the ability to support various owning resources,
// in the form "{Collection}/{Name}", for instance "organizations/my-org".
if strings.ContainsRune(projectID, '/') {
return nil, errors.New("logging: project ID contains '/'")
}
opts = append([]option.ClientOption{
option.WithEndpoint(internal.ProdAddr),
option.WithScopes(WriteScope),
}, opts...)
c, err := vkit.NewClient(ctx, opts...)
if err != nil {
return nil, err
}
c.SetGoogleClientInfo("logging", internal.Version)
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{"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: &mrpb.MonitoredResource{Type: "global"},
Entries: []*logpb.LogEntry{ent},
})
return err
}
// A Logger is used to write log messages to a single log. It can be configured
// with a log ID, common monitored resource, and a set of common labels.
type Logger struct {
client *Client
logName string // "projects/{projectID}/logs/{logID}"
stdLoggers map[Severity]*log.Logger
bundler *bundler.Bundler
// Options
commonResource *mrpb.MonitoredResource
commonLabels map[string]string
}
// A LoggerOption is a configuration option for a Logger.
type LoggerOption interface {
set(*Logger)
}
// CommonResource sets the monitored resource associated with all log entries
// written from a Logger. If not provided, a resource of type "global" is used.
// This value can be overridden 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 }
// 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 {
l := &Logger{
client: c,
logName: internal.LogPath(c.parent(), logID),
commonResource: &mrpb.MonitoredResource{Type: "global"},
}
// 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.Close()
}()
return l
}
type severityWriter struct {
l *Logger
s Severity
}
func (w severityWriter) Write(p []byte) (n int, err error) {
w.l.Log(Entry{
Severity: w.s,
Payload: string(p),
})
return len(p), nil
}
// Close closes the client.
func (c *Client) Close() error {
if c.closed {
return nil
}
close(c.donec) // close Logger bundlers
c.loggers.Wait() // wait for all bundlers to flush and close
// Now there can be no more errors.
close(c.errc) // terminate error goroutine
// Return only the first error. Since all clients share an underlying connection,
// Closes after the first always report a "connection is closing" error.
err := c.client.Close()
c.closed = true
return err
}
// Severity is the severity of the event described in a log entry. These
// guideline severity levels are ordered, with numerically smaller levels
// treated as less severe than numerically larger levels.
type Severity int
const (
// Default means the log entry has no assigned severity level.
Default = Severity(logtypepb.LogSeverity_DEFAULT)
// Debug means debug or trace information.
Debug = Severity(logtypepb.LogSeverity_DEBUG)
// Info means routine information, such as ongoing status or performance.
Info = Severity(logtypepb.LogSeverity_INFO)
// Notice means normal but significant events, such as start up, shut down, or configuration.
Notice = Severity(logtypepb.LogSeverity_NOTICE)
// Warning means events that might cause problems.
Warning = Severity(logtypepb.LogSeverity_WARNING)
// Error means events that are likely to cause problems.
Error = Severity(logtypepb.LogSeverity_ERROR)
// Critical means events that cause more severe problems or brief outages.
Critical = Severity(logtypepb.LogSeverity_CRITICAL)
// Alert means a person must take an action immediately.
Alert = Severity(logtypepb.LogSeverity_ALERT)
// Emergency means one or more systems are unusable.
Emergency = Severity(logtypepb.LogSeverity_EMERGENCY)
)
var severityName = map[Severity]string{
Default: "Default",
Debug: "Debug",
Info: "Info",
Notice: "Notice",
Warning: "Warning",
Error: "Error",
Critical: "Critical",
Alert: "Alert",
Emergency: "Emergency",
}
// String converts a severity level to a string.
func (v Severity) String() string {
// same as proto.EnumName
s, ok := severityName[v]
if ok {
return s
}
return strconv.Itoa(int(v))
}
// ParseSeverity returns the Severity whose name equals s, ignoring case. It
// returns Default if no Severity matches.
func ParseSeverity(s string) Severity {
sl := strings.ToLower(s)
for sev, name := range severityName {
if strings.ToLower(name) == sl {
return sev
}
}
return Default
}
// Entry is a log entry.
// See https://cloud.google.com/logging/docs/view/logs_index for more about entries.
type Entry struct {
// Timestamp is the time of the entry. If zero, the current time is used.
Timestamp time.Time
// Severity is the entry's severity level.
// The zero value is Default.
Severity Severity
// Payload must be either a string or something that
// marshals via the encoding/json package to a JSON object
// (and not any other type of JSON value).
Payload interface{}
// Labels optionally specifies key/value labels for the log entry.
// The Logger.Log method takes ownership of this map. See Logger.CommonLabels
// for more about labels.
Labels map[string]string
// InsertID is a unique ID for the log entry. If you provide this field,
// the logging service considers other log entries in the same log with the
// same ID as duplicates which can be removed. If omitted, the logging
// service will generate a unique ID for this log entry. Note that because
// this client retries RPCs automatically, it is possible (though unlikely)
// that an Entry without an InsertID will be written more than once.
InsertID string
// HTTPRequest optionally specifies metadata about the HTTP request
// associated with this log entry, if applicable. It is optional.
HTTPRequest *HTTPRequest
// Operation optionally provides information about an operation associated
// with the log entry, if applicable.
Operation *logpb.LogEntryOperation
// LogName is the full log name, in the form
// "projects/{ProjectID}/logs/{LogID}". It is set by the client when
// reading entries. It is an error to set it when writing entries.
LogName string
// Resource is the monitored resource associated with the entry. It is set
// by the client when reading entries. It is an error to set it when
// writing entries.
Resource *mrpb.MonitoredResource
}
// 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
// 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 = ""
return &logtypepb.HttpRequest{
RequestMethod: r.Request.Method,
RequestUrl: u.String(),
RequestSize: r.RequestSize,
Status: int32(r.Status),
ResponseSize: r.ResponseSize,
Latency: ptypes.DurationProto(r.Latency),
UserAgent: r.Request.UserAgent(),
RemoteIp: r.RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr?
Referer: r.Request.Referer(),
CacheHit: r.CacheHit,
CacheValidatedWithOriginServer: r.CacheValidatedWithOriginServer,
}
}
// 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{x}}
case float64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{x}}
case string:
return &structpb.Value{Kind: &structpb.Value_StringValue{x}}
case nil:
return &structpb.Value{Kind: &structpb.Value_NullValue{}}
case map[string]interface{}:
return &structpb.Value{Kind: &structpb.Value_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{&structpb.ListValue{vals}}}
default:
panic(fmt.Sprintf("bad type %T for JSON value", v))
}
}
// LogSync logs the Entry synchronously without any buffering. Because LogSync is slow
// and will block, it is intended primarily for debugging or critical errors.
// Prefer Log for most uses.
// TODO(jba): come up with a better name (LogNow?) or eliminate.
func (l *Logger) LogSync(ctx context.Context, e Entry) error {
ent, err := toLogEntry(e)
if err != nil {
return err
}
_, err = l.client.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
LogName: l.logName,
Resource: l.commonResource,
Labels: l.commonLabels,
Entries: []*logpb.LogEntry{ent},
})
return err
}
// Log buffers the Entry for output to the logging service. It never blocks.
func (l *Logger) Log(e Entry) {
ent, err := toLogEntry(e)
if err != nil {
l.error(err)
return
}
if err := l.bundler.Add(ent, proto.Size(ent)); err != nil {
l.error(err)
}
}
// Flush blocks until all currently buffered log entries are sent.
func (l *Logger) Flush() {
l.bundler.Flush()
}
func (l *Logger) writeLogEntries(ctx context.Context, entries []*logpb.LogEntry) {
req := &logpb.WriteLogEntriesRequest{
LogName: l.logName,
Resource: l.commonResource,
Labels: l.commonLabels,
Entries: entries,
}
_, err := l.client.client.WriteLogEntries(ctx, req)
if err != nil {
l.error(err)
}
}
// error puts the error on the client's error channel
// without blocking.
func (l *Logger) error(err error) {
select {
case l.client.errc <- err:
default:
}
}
// StandardLogger returns a *log.Logger for the provided severity.
//
// This method is cheap. A single log.Logger is pre-allocated for each
// severity level in each Logger. Callers may mutate the returned log.Logger
// (for example by calling SetFlags or SetPrefix).
func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] }
func trunc32(i int) int32 {
if i > math.MaxInt32 {
i = math.MaxInt32
}
return int32(i)
}
func toLogEntry(e Entry) (*logpb.LogEntry, error) {
if e.LogName != "" {
return nil, errors.New("logging: Entry.LogName should be not be set when writing")
}
t := e.Timestamp
if t.IsZero() {
t = now()
}
ts, err := ptypes.TimestampProto(t)
if err != nil {
return nil, err
}
ent := &logpb.LogEntry{
Timestamp: ts,
Severity: logtypepb.LogSeverity(e.Severity),
InsertId: e.InsertID,
HttpRequest: fromHTTPRequest(e.HTTPRequest),
Operation: e.Operation,
Labels: e.Labels,
}
switch p := e.Payload.(type) {
case string:
ent.Payload = &logpb.LogEntry_TextPayload{p}
default:
s, err := toProtoStruct(p)
if err != nil {
return nil, err
}
ent.Payload = &logpb.LogEntry_JsonPayload{s}
}
return ent, nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。