Source File
logging.go
Belonging Package
cloud.google.com/go/logging
ReadScope = "https://www.googleapis.com/auth/logging.read"
WriteScope = "https://www.googleapis.com/auth/logging.write"
AdminScope = "https://www.googleapis.com/auth/logging.admin"
)
defaultErrorCapacity = 10
DefaultEntryCountThreshold = 1000
DefaultEntryByteThreshold = 1 << 20 // 1MiB
DefaultBufferedByteLimit = 1 << 30 // 1GiB
defaultWriteTimeout = 10 * time.Minute
)
var ErrOverflow = bundler.ErrOverflow
type Client struct {
client *vkit.Client // client for the logging service
parent string // e.g. "projects/proj-id"
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
func ( context.Context, string, ...option.ClientOption) (*Client, error) {
if !strings.ContainsRune(, '/') {
= "projects/" +
}
= append([]option.ClientOption{
option.WithEndpoint(internal.ProdAddr),
option.WithScopes(WriteScope),
}, ...)
, := vkit.NewClient(, ...)
if != nil {
return nil,
}
.SetGoogleClientInfo("gccl", version.Repo)
:= &Client{
client: ,
parent: ,
errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors
donec: make(chan struct{}),
OnError: func( error) { log.Printf("logging client: %v", ) },
go func() {
func ( *Client) ( context.Context) error {
:= &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.
}
, := .client.WriteLogEntries(, &logpb.WriteLogEntriesRequest{
LogName: internal.LogPath(.parent, "ping"),
Resource: monitoredResource(.parent),
Entries: []*logpb.LogEntry{},
})
return
}
commonResource *mrpb.MonitoredResource
commonLabels map[string]string
ctxFunc func() (context.Context, func())
}
type LoggerOption interface {
set(*Logger)
}
func ( *mrpb.MonitoredResource) LoggerOption { return commonResource{} }
type commonResource struct{ *mrpb.MonitoredResource }
func ( commonResource) ( *Logger) { .commonResource = .MonitoredResource }
var detectedResource struct {
pb *mrpb.MonitoredResource
once sync.Once
}
func () *mrpb.MonitoredResource {
detectedResource.once.Do(func() {
if !metadata.OnGCE() {
return
}
, := metadata.ProjectID()
if != nil {
return
}
, := metadata.InstanceID()
if != nil {
return
}
, := metadata.Zone()
if != nil {
return
}
, := metadata.InstanceName()
if != nil {
return
}
detectedResource.pb = &mrpb.MonitoredResource{
Type: "gce_instance",
Labels: map[string]string{
"project_id": ,
"instance_id": ,
"instance_name": ,
"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 ( string) *mrpb.MonitoredResource {
:= strings.SplitN(, "/", 2)
if len() != 2 {
return globalResource()
}
, := resourceInfo[[0]]
if ! {
return globalResource([1])
}
return &mrpb.MonitoredResource{
Type: .rtype,
Labels: map[string]string{.label: [1]},
}
}
func ( string) *mrpb.MonitoredResource {
return &mrpb.MonitoredResource{
Type: "global",
Labels: map[string]string{
"project_id": ,
},
}
}
func ( map[string]string) LoggerOption { return commonLabels() }
type commonLabels map[string]string
func ( commonLabels) ( *Logger) { .commonLabels = }
func ( int) LoggerOption { return concurrentWriteLimit() }
type concurrentWriteLimit int
func ( concurrentWriteLimit) ( *Logger) { .bundler.HandlerLimit = int() }
func ( time.Duration) LoggerOption { return delayThreshold() }
type delayThreshold time.Duration
func ( delayThreshold) ( *Logger) { .bundler.DelayThreshold = time.Duration() }
func ( int) LoggerOption { return entryCountThreshold() }
type entryCountThreshold int
func ( entryCountThreshold) ( *Logger) { .bundler.BundleCountThreshold = int() }
func ( int) LoggerOption { return entryByteThreshold() }
type entryByteThreshold int
func ( entryByteThreshold) ( *Logger) { .bundler.BundleByteThreshold = int() }
func ( int) LoggerOption { return entryByteLimit() }
type entryByteLimit int
func ( entryByteLimit) ( *Logger) { .bundler.BundleByteLimit = int() }
func ( int) LoggerOption { return bufferedByteLimit() }
type bufferedByteLimit int
func ( bufferedByteLimit) ( *Logger) { .bundler.BufferedByteLimit = int() }
func ( func() ( context.Context, func())) LoggerOption {
return contextFunc()
}
type contextFunc func() (ctx context.Context, afterCall func())
func ( contextFunc) ( *Logger) { .ctxFunc = }
func ( *Client) ( string, ...LoggerOption) *Logger {
:= detectResource()
if == nil {
= monitoredResource(.parent)
}
:= &Logger{
client: ,
logName: internal.LogPath(.parent, ),
commonResource: ,
ctxFunc: func() (context.Context, func()) { return context.Background(), nil },
}
.bundler = bundler.NewBundler(&logpb.LogEntry{}, func( interface{}) {
.writeLogEntries(.([]*logpb.LogEntry))
})
.bundler.DelayThreshold = DefaultDelayThreshold
.bundler.BundleCountThreshold = DefaultEntryCountThreshold
.bundler.BundleByteThreshold = DefaultEntryByteThreshold
.bundler.BufferedByteLimit = DefaultBufferedByteLimit
for , := range {
.set()
}
.stdLoggers = map[Severity]*log.Logger{}
for := range severityName {
.stdLoggers[] = log.New(severityWriter{, }, "", 0)
}
, := severityName[]
if {
return
}
return strconv.Itoa(int())
}
Payload interface{}
CacheValidatedWithOriginServer bool
}
func ( *HTTPRequest) *logtypepb.HttpRequest {
if == nil {
return nil
}
if .Request == nil {
panic("HTTPRequest must have a non-nil Request")
}
:= *.Request.URL
.Fragment = ""
:= &logtypepb.HttpRequest{
RequestMethod: .Request.Method,
RequestUrl: fixUTF8(.String()),
RequestSize: .RequestSize,
Status: int32(.Status),
ResponseSize: .ResponseSize,
UserAgent: .Request.UserAgent(),
ServerIp: .LocalIP,
RemoteIp: .RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr?
Referer: .Request.Referer(),
CacheHit: .CacheHit,
CacheValidatedWithOriginServer: .CacheValidatedWithOriginServer,
}
if .Latency != 0 {
.Latency = ptypes.DurationProto(.Latency)
}
return
}
func ( string) string {
if utf8.ValidString() {
return
}
var []byte
var error
if , := .(json.RawMessage); { // needed for Go 1.7 and below
= []byte()
} else {
, = json.Marshal()
if != nil {
return nil, fmt.Errorf("logging: json.Marshal: %v", )
}
}
var map[string]interface{}
= json.Unmarshal(, &)
if != nil {
return nil, fmt.Errorf("logging: json.Unmarshal: %v", )
}
return jsonMapToProtoStruct(), nil
}
func ( map[string]interface{}) *structpb.Struct {
:= map[string]*structpb.Value{}
for , := range {
[] = jsonValueToStructValue()
}
return &structpb.Struct{Fields: }
}
func ( interface{}) *structpb.Value {
switch x := .(type) {
case bool:
return &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: }}
case float64:
return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: }}
case string:
return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: }}
case nil:
return &structpb.Value{Kind: &structpb.Value_NullValue{}}
case map[string]interface{}:
return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: jsonMapToProtoStruct()}}
case []interface{}:
var []*structpb.Value
for , := range {
= append(, ())
}
return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: }}}
default:
panic(fmt.Sprintf("bad type %T for JSON value", ))
}
}
func ( *Logger) ( context.Context, Entry) error {
, := .toLogEntry()
if != nil {
return
}
_, = .client.client.WriteLogEntries(, &logpb.WriteLogEntriesRequest{
LogName: .logName,
Resource: .commonResource,
Labels: .commonLabels,
Entries: []*logpb.LogEntry{},
})
return
}
func ( *Logger) () error {
.bundler.Flush()
return .client.extractErrorInfo()
}
func ( *Logger) ( []*logpb.LogEntry) {
:= &logpb.WriteLogEntriesRequest{
LogName: .logName,
Resource: .commonResource,
Labels: .commonLabels,
Entries: ,
}
, := .ctxFunc()
, := context.WithTimeout(, defaultWriteTimeout)
defer ()
, := .client.client.WriteLogEntries(, )
if != nil {
.client.error()
}
if != nil {
()
}
}
func ( *Logger) ( Severity) *log.Logger { return .stdLoggers[] }
var reCloudTraceContext = regexp.MustCompile(`([a-f\d]+)/([a-f\d]+);o=(\d)`)
:= reCloudTraceContext.FindAllStringSubmatch(, -1)
if len() != 1 {
return
}
:= [0]
if len() != 4 {
return
}
, = [1], [2]
if == "0" {
= ""
}
= [3] == "1"
return
}
func ( *Logger) ( Entry) (*logpb.LogEntry, error) {
if .LogName != "" {
return nil, errors.New("logging: Entry.LogName should be not be set when writing")
}
:= .Timestamp
if .IsZero() {
= now()
}
, := ptypes.TimestampProto()
if != nil {
return nil,
}
if .Trace == "" && .HTTPRequest != nil && .HTTPRequest.Request != nil {
:= .HTTPRequest.Request.Header.Get("X-Cloud-Trace-Context")
.TraceSampled = .TraceSampled ||
}
}
:= &logpb.LogEntry{
Timestamp: ,
Severity: logtypepb.LogSeverity(.Severity),
InsertId: .InsertID,
HttpRequest: fromHTTPRequest(.HTTPRequest),
Operation: .Operation,
Labels: .Labels,
Trace: .Trace,
SpanId: .SpanID,
Resource: .Resource,
SourceLocation: .SourceLocation,
TraceSampled: .TraceSampled,
}
switch p := .Payload.(type) {
case string:
.Payload = &logpb.LogEntry_TextPayload{TextPayload: }
default:
, := toProtoStruct()
if != nil {
return nil,
}
.Payload = &logpb.LogEntry_JsonPayload{JsonPayload: }
}
return , nil
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |