logging.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. // Copyright 2016 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // API/gRPC features intentionally missing from this client:
  15. // - You cannot have the server pick the time of the entry. This client
  16. // always sends a time.
  17. // - There is no way to provide a protocol buffer payload.
  18. // - No support for the "partial success" feature when writing log entries.
  19. // TODO(jba): test whether forward-slash characters in the log ID must be URL-encoded.
  20. // These features are missing now, but will likely be added:
  21. // - There is no way to specify CallOptions.
  22. package logging
  23. import (
  24. "encoding/json"
  25. "errors"
  26. "fmt"
  27. "log"
  28. "math"
  29. "net/http"
  30. "strconv"
  31. "strings"
  32. "sync"
  33. "time"
  34. vkit "cloud.google.com/go/logging/apiv2"
  35. "cloud.google.com/go/logging/internal"
  36. "github.com/golang/protobuf/proto"
  37. "github.com/golang/protobuf/ptypes"
  38. structpb "github.com/golang/protobuf/ptypes/struct"
  39. tspb "github.com/golang/protobuf/ptypes/timestamp"
  40. "golang.org/x/net/context"
  41. "google.golang.org/api/option"
  42. "google.golang.org/api/support/bundler"
  43. mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
  44. logtypepb "google.golang.org/genproto/googleapis/logging/type"
  45. logpb "google.golang.org/genproto/googleapis/logging/v2"
  46. )
  47. const (
  48. // Scope for reading from the logging service.
  49. ReadScope = "https://www.googleapis.com/auth/logging.read"
  50. // Scope for writing to the logging service.
  51. WriteScope = "https://www.googleapis.com/auth/logging.write"
  52. // Scope for administrative actions on the logging service.
  53. AdminScope = "https://www.googleapis.com/auth/logging.admin"
  54. )
  55. const (
  56. // defaultErrorCapacity is the capacity of the channel used to deliver
  57. // errors to the OnError function.
  58. defaultErrorCapacity = 10
  59. // DefaultDelayThreshold is the default value for the DelayThreshold LoggerOption.
  60. DefaultDelayThreshold = time.Second
  61. // DefaultEntryCountThreshold is the default value for the EntryCountThreshold LoggerOption.
  62. DefaultEntryCountThreshold = 1000
  63. // DefaultEntryByteThreshold is the default value for the EntryByteThreshold LoggerOption.
  64. DefaultEntryByteThreshold = 1 << 20 // 1MiB
  65. // DefaultBufferedByteLimit is the default value for the BufferedByteLimit LoggerOption.
  66. DefaultBufferedByteLimit = 1 << 30 // 1GiB
  67. )
  68. // For testing:
  69. var now = time.Now
  70. // ErrOverflow signals that the number of buffered entries for a Logger
  71. // exceeds its BufferLimit.
  72. var ErrOverflow = errors.New("logging: log entry overflowed buffer limits")
  73. // Client is a Logging client. A Client is associated with a single Cloud project.
  74. type Client struct {
  75. client *vkit.Client // client for the logging service
  76. projectID string
  77. errc chan error // should be buffered to minimize dropped errors
  78. donec chan struct{} // closed on Client.Close to close Logger bundlers
  79. loggers sync.WaitGroup // so we can wait for loggers to close
  80. closed bool
  81. // OnError is called when an error occurs in a call to Log or Flush. The
  82. // error may be due to an invalid Entry, an overflow because BufferLimit
  83. // was reached (in which case the error will be ErrOverflow) or an error
  84. // communicating with the logging service. OnError is called with errors
  85. // from all Loggers. It is never called concurrently. OnError is expected
  86. // to return quickly; if errors occur while OnError is running, some may
  87. // not be reported. The default behavior is to call log.Printf.
  88. //
  89. // This field should be set only once, before any method of Client is called.
  90. OnError func(err error)
  91. }
  92. // NewClient returns a new logging client associated with the provided project ID.
  93. //
  94. // By default NewClient uses WriteScope. To use a different scope, call
  95. // NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes).
  96. func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
  97. // Check for '/' in project ID to reserve the ability to support various owning resources,
  98. // in the form "{Collection}/{Name}", for instance "organizations/my-org".
  99. if strings.ContainsRune(projectID, '/') {
  100. return nil, errors.New("logging: project ID contains '/'")
  101. }
  102. opts = append([]option.ClientOption{
  103. option.WithEndpoint(internal.ProdAddr),
  104. option.WithScopes(WriteScope),
  105. }, opts...)
  106. c, err := vkit.NewClient(ctx, opts...)
  107. if err != nil {
  108. return nil, err
  109. }
  110. c.SetGoogleClientInfo("logging", internal.Version)
  111. client := &Client{
  112. client: c,
  113. projectID: projectID,
  114. errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors
  115. donec: make(chan struct{}),
  116. OnError: func(e error) { log.Printf("logging client: %v", e) },
  117. }
  118. // Call the user's function synchronously, to make life easier for them.
  119. go func() {
  120. for err := range client.errc {
  121. // This reference to OnError is memory-safe if the user sets OnError before
  122. // calling any client methods. The reference happens before the first read from
  123. // client.errc, which happens before the first write to client.errc, which
  124. // happens before any call, which happens before the user sets OnError.
  125. if fn := client.OnError; fn != nil {
  126. fn(err)
  127. } else {
  128. log.Printf("logging (project ID %q): %v", projectID, err)
  129. }
  130. }
  131. }()
  132. return client, nil
  133. }
  134. // parent returns the string used in many RPCs to denote the parent resource of the log.
  135. func (c *Client) parent() string {
  136. return "projects/" + c.projectID
  137. }
  138. var unixZeroTimestamp *tspb.Timestamp
  139. func init() {
  140. var err error
  141. unixZeroTimestamp, err = ptypes.TimestampProto(time.Unix(0, 0))
  142. if err != nil {
  143. panic(err)
  144. }
  145. }
  146. // Ping reports whether the client's connection to the logging service and the
  147. // authentication configuration are valid. To accomplish this, Ping writes a
  148. // log entry "ping" to a log named "ping".
  149. func (c *Client) Ping(ctx context.Context) error {
  150. ent := &logpb.LogEntry{
  151. Payload: &logpb.LogEntry_TextPayload{"ping"},
  152. Timestamp: unixZeroTimestamp, // Identical timestamps and insert IDs are both
  153. InsertId: "ping", // necessary for the service to dedup these entries.
  154. }
  155. _, err := c.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
  156. LogName: internal.LogPath(c.parent(), "ping"),
  157. Resource: &mrpb.MonitoredResource{Type: "global"},
  158. Entries: []*logpb.LogEntry{ent},
  159. })
  160. return err
  161. }
  162. // A Logger is used to write log messages to a single log. It can be configured
  163. // with a log ID, common monitored resource, and a set of common labels.
  164. type Logger struct {
  165. client *Client
  166. logName string // "projects/{projectID}/logs/{logID}"
  167. stdLoggers map[Severity]*log.Logger
  168. bundler *bundler.Bundler
  169. // Options
  170. commonResource *mrpb.MonitoredResource
  171. commonLabels map[string]string
  172. }
  173. // A LoggerOption is a configuration option for a Logger.
  174. type LoggerOption interface {
  175. set(*Logger)
  176. }
  177. // CommonResource sets the monitored resource associated with all log entries
  178. // written from a Logger. If not provided, a resource of type "global" is used.
  179. // This value can be overridden by setting an Entry's Resource field.
  180. func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} }
  181. type commonResource struct{ *mrpb.MonitoredResource }
  182. func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource }
  183. // CommonLabels are labels that apply to all log entries written from a Logger,
  184. // so that you don't have to repeat them in each log entry's Labels field. If
  185. // any of the log entries contains a (key, value) with the same key that is in
  186. // CommonLabels, then the entry's (key, value) overrides the one in
  187. // CommonLabels.
  188. func CommonLabels(m map[string]string) LoggerOption { return commonLabels(m) }
  189. type commonLabels map[string]string
  190. func (c commonLabels) set(l *Logger) { l.commonLabels = c }
  191. // DelayThreshold is the maximum amount of time that an entry should remain
  192. // buffered in memory before a call to the logging service is triggered. Larger
  193. // values of DelayThreshold will generally result in fewer calls to the logging
  194. // service, while increasing the risk that log entries will be lost if the
  195. // process crashes.
  196. // The default is DefaultDelayThreshold.
  197. func DelayThreshold(d time.Duration) LoggerOption { return delayThreshold(d) }
  198. type delayThreshold time.Duration
  199. func (d delayThreshold) set(l *Logger) { l.bundler.DelayThreshold = time.Duration(d) }
  200. // EntryCountThreshold is the maximum number of entries that will be buffered
  201. // in memory before a call to the logging service is triggered. Larger values
  202. // will generally result in fewer calls to the logging service, while
  203. // increasing both memory consumption and the risk that log entries will be
  204. // lost if the process crashes.
  205. // The default is DefaultEntryCountThreshold.
  206. func EntryCountThreshold(n int) LoggerOption { return entryCountThreshold(n) }
  207. type entryCountThreshold int
  208. func (e entryCountThreshold) set(l *Logger) { l.bundler.BundleCountThreshold = int(e) }
  209. // EntryByteThreshold is the maximum number of bytes of entries that will be
  210. // buffered in memory before a call to the logging service is triggered. See
  211. // EntryCountThreshold for a discussion of the tradeoffs involved in setting
  212. // this option.
  213. // The default is DefaultEntryByteThreshold.
  214. func EntryByteThreshold(n int) LoggerOption { return entryByteThreshold(n) }
  215. type entryByteThreshold int
  216. func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) }
  217. // EntryByteLimit is the maximum number of bytes of entries that will be sent
  218. // in a single call to the logging service. This option limits the size of a
  219. // single RPC payload, to account for network or service issues with large
  220. // RPCs. If EntryByteLimit is smaller than EntryByteThreshold, the latter has
  221. // no effect.
  222. // The default is zero, meaning there is no limit.
  223. func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) }
  224. type entryByteLimit int
  225. func (e entryByteLimit) set(l *Logger) { l.bundler.BundleByteLimit = int(e) }
  226. // BufferedByteLimit is the maximum number of bytes that the Logger will keep
  227. // in memory before returning ErrOverflow. This option limits the total memory
  228. // consumption of the Logger (but note that each Logger has its own, separate
  229. // limit). It is possible to reach BufferedByteLimit even if it is larger than
  230. // EntryByteThreshold or EntryByteLimit, because calls triggered by the latter
  231. // two options may be enqueued (and hence occupying memory) while new log
  232. // entries are being added.
  233. // The default is DefaultBufferedByteLimit.
  234. func BufferedByteLimit(n int) LoggerOption { return bufferedByteLimit(n) }
  235. type bufferedByteLimit int
  236. func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b) }
  237. // Logger returns a Logger that will write entries with the given log ID, such as
  238. // "syslog". A log ID must be less than 512 characters long and can only
  239. // include the following characters: upper and lower case alphanumeric
  240. // characters: [A-Za-z0-9]; and punctuation characters: forward-slash,
  241. // underscore, hyphen, and period.
  242. func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger {
  243. l := &Logger{
  244. client: c,
  245. logName: internal.LogPath(c.parent(), logID),
  246. commonResource: &mrpb.MonitoredResource{Type: "global"},
  247. }
  248. // TODO(jba): determine the right context for the bundle handler.
  249. ctx := context.TODO()
  250. l.bundler = bundler.NewBundler(&logpb.LogEntry{}, func(entries interface{}) {
  251. l.writeLogEntries(ctx, entries.([]*logpb.LogEntry))
  252. })
  253. l.bundler.DelayThreshold = DefaultDelayThreshold
  254. l.bundler.BundleCountThreshold = DefaultEntryCountThreshold
  255. l.bundler.BundleByteThreshold = DefaultEntryByteThreshold
  256. l.bundler.BufferedByteLimit = DefaultBufferedByteLimit
  257. for _, opt := range opts {
  258. opt.set(l)
  259. }
  260. l.stdLoggers = map[Severity]*log.Logger{}
  261. for s := range severityName {
  262. l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0)
  263. }
  264. c.loggers.Add(1)
  265. go func() {
  266. defer c.loggers.Done()
  267. <-c.donec
  268. l.bundler.Close()
  269. }()
  270. return l
  271. }
  272. type severityWriter struct {
  273. l *Logger
  274. s Severity
  275. }
  276. func (w severityWriter) Write(p []byte) (n int, err error) {
  277. w.l.Log(Entry{
  278. Severity: w.s,
  279. Payload: string(p),
  280. })
  281. return len(p), nil
  282. }
  283. // Close closes the client.
  284. func (c *Client) Close() error {
  285. if c.closed {
  286. return nil
  287. }
  288. close(c.donec) // close Logger bundlers
  289. c.loggers.Wait() // wait for all bundlers to flush and close
  290. // Now there can be no more errors.
  291. close(c.errc) // terminate error goroutine
  292. // Return only the first error. Since all clients share an underlying connection,
  293. // Closes after the first always report a "connection is closing" error.
  294. err := c.client.Close()
  295. c.closed = true
  296. return err
  297. }
  298. // Severity is the severity of the event described in a log entry. These
  299. // guideline severity levels are ordered, with numerically smaller levels
  300. // treated as less severe than numerically larger levels.
  301. type Severity int
  302. const (
  303. // Default means the log entry has no assigned severity level.
  304. Default = Severity(logtypepb.LogSeverity_DEFAULT)
  305. // Debug means debug or trace information.
  306. Debug = Severity(logtypepb.LogSeverity_DEBUG)
  307. // Info means routine information, such as ongoing status or performance.
  308. Info = Severity(logtypepb.LogSeverity_INFO)
  309. // Notice means normal but significant events, such as start up, shut down, or configuration.
  310. Notice = Severity(logtypepb.LogSeverity_NOTICE)
  311. // Warning means events that might cause problems.
  312. Warning = Severity(logtypepb.LogSeverity_WARNING)
  313. // Error means events that are likely to cause problems.
  314. Error = Severity(logtypepb.LogSeverity_ERROR)
  315. // Critical means events that cause more severe problems or brief outages.
  316. Critical = Severity(logtypepb.LogSeverity_CRITICAL)
  317. // Alert means a person must take an action immediately.
  318. Alert = Severity(logtypepb.LogSeverity_ALERT)
  319. // Emergency means one or more systems are unusable.
  320. Emergency = Severity(logtypepb.LogSeverity_EMERGENCY)
  321. )
  322. var severityName = map[Severity]string{
  323. Default: "Default",
  324. Debug: "Debug",
  325. Info: "Info",
  326. Notice: "Notice",
  327. Warning: "Warning",
  328. Error: "Error",
  329. Critical: "Critical",
  330. Alert: "Alert",
  331. Emergency: "Emergency",
  332. }
  333. // String converts a severity level to a string.
  334. func (v Severity) String() string {
  335. // same as proto.EnumName
  336. s, ok := severityName[v]
  337. if ok {
  338. return s
  339. }
  340. return strconv.Itoa(int(v))
  341. }
  342. // ParseSeverity returns the Severity whose name equals s, ignoring case. It
  343. // returns Default if no Severity matches.
  344. func ParseSeverity(s string) Severity {
  345. sl := strings.ToLower(s)
  346. for sev, name := range severityName {
  347. if strings.ToLower(name) == sl {
  348. return sev
  349. }
  350. }
  351. return Default
  352. }
  353. // Entry is a log entry.
  354. // See https://cloud.google.com/logging/docs/view/logs_index for more about entries.
  355. type Entry struct {
  356. // Timestamp is the time of the entry. If zero, the current time is used.
  357. Timestamp time.Time
  358. // Severity is the entry's severity level.
  359. // The zero value is Default.
  360. Severity Severity
  361. // Payload must be either a string or something that
  362. // marshals via the encoding/json package to a JSON object
  363. // (and not any other type of JSON value).
  364. Payload interface{}
  365. // Labels optionally specifies key/value labels for the log entry.
  366. // The Logger.Log method takes ownership of this map. See Logger.CommonLabels
  367. // for more about labels.
  368. Labels map[string]string
  369. // InsertID is a unique ID for the log entry. If you provide this field,
  370. // the logging service considers other log entries in the same log with the
  371. // same ID as duplicates which can be removed. If omitted, the logging
  372. // service will generate a unique ID for this log entry. Note that because
  373. // this client retries RPCs automatically, it is possible (though unlikely)
  374. // that an Entry without an InsertID will be written more than once.
  375. InsertID string
  376. // HTTPRequest optionally specifies metadata about the HTTP request
  377. // associated with this log entry, if applicable. It is optional.
  378. HTTPRequest *HTTPRequest
  379. // Operation optionally provides information about an operation associated
  380. // with the log entry, if applicable.
  381. Operation *logpb.LogEntryOperation
  382. // LogName is the full log name, in the form
  383. // "projects/{ProjectID}/logs/{LogID}". It is set by the client when
  384. // reading entries. It is an error to set it when writing entries.
  385. LogName string
  386. // Resource is the monitored resource associated with the entry. It is set
  387. // by the client when reading entries. It is an error to set it when
  388. // writing entries.
  389. Resource *mrpb.MonitoredResource
  390. }
  391. // HTTPRequest contains an http.Request as well as additional
  392. // information about the request and its response.
  393. type HTTPRequest struct {
  394. // Request is the http.Request passed to the handler.
  395. Request *http.Request
  396. // RequestSize is the size of the HTTP request message in bytes, including
  397. // the request headers and the request body.
  398. RequestSize int64
  399. // Status is the response code indicating the status of the response.
  400. // Examples: 200, 404.
  401. Status int
  402. // ResponseSize is the size of the HTTP response message sent back to the client, in bytes,
  403. // including the response headers and the response body.
  404. ResponseSize int64
  405. // Latency is the request processing latency on the server, from the time the request was
  406. // received until the response was sent.
  407. Latency time.Duration
  408. // RemoteIP is the IP address (IPv4 or IPv6) of the client that issued the
  409. // HTTP request. Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329".
  410. RemoteIP string
  411. // CacheHit reports whether an entity was served from cache (with or without
  412. // validation).
  413. CacheHit bool
  414. // CacheValidatedWithOriginServer reports whether the response was
  415. // validated with the origin server before being served from cache. This
  416. // field is only meaningful if CacheHit is true.
  417. CacheValidatedWithOriginServer bool
  418. }
  419. func fromHTTPRequest(r *HTTPRequest) *logtypepb.HttpRequest {
  420. if r == nil {
  421. return nil
  422. }
  423. if r.Request == nil {
  424. panic("HTTPRequest must have a non-nil Request")
  425. }
  426. u := *r.Request.URL
  427. u.Fragment = ""
  428. return &logtypepb.HttpRequest{
  429. RequestMethod: r.Request.Method,
  430. RequestUrl: u.String(),
  431. RequestSize: r.RequestSize,
  432. Status: int32(r.Status),
  433. ResponseSize: r.ResponseSize,
  434. Latency: ptypes.DurationProto(r.Latency),
  435. UserAgent: r.Request.UserAgent(),
  436. RemoteIp: r.RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr?
  437. Referer: r.Request.Referer(),
  438. CacheHit: r.CacheHit,
  439. CacheValidatedWithOriginServer: r.CacheValidatedWithOriginServer,
  440. }
  441. }
  442. // toProtoStruct converts v, which must marshal into a JSON object,
  443. // into a Google Struct proto.
  444. func toProtoStruct(v interface{}) (*structpb.Struct, error) {
  445. // Fast path: if v is already a *structpb.Struct, nothing to do.
  446. if s, ok := v.(*structpb.Struct); ok {
  447. return s, nil
  448. }
  449. // v is a Go struct that supports JSON marshalling. We want a Struct
  450. // protobuf. Some day we may have a more direct way to get there, but right
  451. // now the only way is to marshal the Go struct to JSON, unmarshal into a
  452. // map, and then build the Struct proto from the map.
  453. jb, err := json.Marshal(v)
  454. if err != nil {
  455. return nil, fmt.Errorf("logging: json.Marshal: %v", err)
  456. }
  457. var m map[string]interface{}
  458. err = json.Unmarshal(jb, &m)
  459. if err != nil {
  460. return nil, fmt.Errorf("logging: json.Unmarshal: %v", err)
  461. }
  462. return jsonMapToProtoStruct(m), nil
  463. }
  464. func jsonMapToProtoStruct(m map[string]interface{}) *structpb.Struct {
  465. fields := map[string]*structpb.Value{}
  466. for k, v := range m {
  467. fields[k] = jsonValueToStructValue(v)
  468. }
  469. return &structpb.Struct{Fields: fields}
  470. }
  471. func jsonValueToStructValue(v interface{}) *structpb.Value {
  472. switch x := v.(type) {
  473. case bool:
  474. return &structpb.Value{Kind: &structpb.Value_BoolValue{x}}
  475. case float64:
  476. return &structpb.Value{Kind: &structpb.Value_NumberValue{x}}
  477. case string:
  478. return &structpb.Value{Kind: &structpb.Value_StringValue{x}}
  479. case nil:
  480. return &structpb.Value{Kind: &structpb.Value_NullValue{}}
  481. case map[string]interface{}:
  482. return &structpb.Value{Kind: &structpb.Value_StructValue{jsonMapToProtoStruct(x)}}
  483. case []interface{}:
  484. var vals []*structpb.Value
  485. for _, e := range x {
  486. vals = append(vals, jsonValueToStructValue(e))
  487. }
  488. return &structpb.Value{Kind: &structpb.Value_ListValue{&structpb.ListValue{vals}}}
  489. default:
  490. panic(fmt.Sprintf("bad type %T for JSON value", v))
  491. }
  492. }
  493. // LogSync logs the Entry synchronously without any buffering. Because LogSync is slow
  494. // and will block, it is intended primarily for debugging or critical errors.
  495. // Prefer Log for most uses.
  496. // TODO(jba): come up with a better name (LogNow?) or eliminate.
  497. func (l *Logger) LogSync(ctx context.Context, e Entry) error {
  498. ent, err := toLogEntry(e)
  499. if err != nil {
  500. return err
  501. }
  502. _, err = l.client.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{
  503. LogName: l.logName,
  504. Resource: l.commonResource,
  505. Labels: l.commonLabels,
  506. Entries: []*logpb.LogEntry{ent},
  507. })
  508. return err
  509. }
  510. // Log buffers the Entry for output to the logging service. It never blocks.
  511. func (l *Logger) Log(e Entry) {
  512. ent, err := toLogEntry(e)
  513. if err != nil {
  514. l.error(err)
  515. return
  516. }
  517. if err := l.bundler.Add(ent, proto.Size(ent)); err != nil {
  518. l.error(err)
  519. }
  520. }
  521. // Flush blocks until all currently buffered log entries are sent.
  522. func (l *Logger) Flush() {
  523. l.bundler.Flush()
  524. }
  525. func (l *Logger) writeLogEntries(ctx context.Context, entries []*logpb.LogEntry) {
  526. req := &logpb.WriteLogEntriesRequest{
  527. LogName: l.logName,
  528. Resource: l.commonResource,
  529. Labels: l.commonLabels,
  530. Entries: entries,
  531. }
  532. _, err := l.client.client.WriteLogEntries(ctx, req)
  533. if err != nil {
  534. l.error(err)
  535. }
  536. }
  537. // error puts the error on the client's error channel
  538. // without blocking.
  539. func (l *Logger) error(err error) {
  540. select {
  541. case l.client.errc <- err:
  542. default:
  543. }
  544. }
  545. // StandardLogger returns a *log.Logger for the provided severity.
  546. //
  547. // This method is cheap. A single log.Logger is pre-allocated for each
  548. // severity level in each Logger. Callers may mutate the returned log.Logger
  549. // (for example by calling SetFlags or SetPrefix).
  550. func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] }
  551. func trunc32(i int) int32 {
  552. if i > math.MaxInt32 {
  553. i = math.MaxInt32
  554. }
  555. return int32(i)
  556. }
  557. func toLogEntry(e Entry) (*logpb.LogEntry, error) {
  558. if e.LogName != "" {
  559. return nil, errors.New("logging: Entry.LogName should be not be set when writing")
  560. }
  561. t := e.Timestamp
  562. if t.IsZero() {
  563. t = now()
  564. }
  565. ts, err := ptypes.TimestampProto(t)
  566. if err != nil {
  567. return nil, err
  568. }
  569. ent := &logpb.LogEntry{
  570. Timestamp: ts,
  571. Severity: logtypepb.LogSeverity(e.Severity),
  572. InsertId: e.InsertID,
  573. HttpRequest: fromHTTPRequest(e.HTTPRequest),
  574. Operation: e.Operation,
  575. Labels: e.Labels,
  576. }
  577. switch p := e.Payload.(type) {
  578. case string:
  579. ent.Payload = &logpb.LogEntry_TextPayload{p}
  580. default:
  581. s, err := toProtoStruct(p)
  582. if err != nil {
  583. return nil, err
  584. }
  585. ent.Payload = &logpb.LogEntry_JsonPayload{s}
  586. }
  587. return ent, nil
  588. }