You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

169 lines
5.2 KiB

  1. // Copyright 2016 Google LLC
  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. package logadmin
  15. import (
  16. "fmt"
  17. vkit "cloud.google.com/go/logging/apiv2"
  18. "golang.org/x/net/context"
  19. "google.golang.org/api/iterator"
  20. logpb "google.golang.org/genproto/googleapis/logging/v2"
  21. )
  22. // Sink describes a sink used to export log entries outside Stackdriver
  23. // Logging. Incoming log entries matching a filter are exported to a
  24. // destination (a Cloud Storage bucket, BigQuery dataset or Cloud Pub/Sub
  25. // topic).
  26. //
  27. // For more information, see https://cloud.google.com/logging/docs/export/using_exported_logs.
  28. // (The Sinks in this package are what the documentation refers to as "project sinks".)
  29. type Sink struct {
  30. // ID is a client-assigned sink identifier. Example:
  31. // "my-severe-errors-to-pubsub".
  32. // Sink identifiers are limited to 1000 characters
  33. // and can include only the following characters: A-Z, a-z,
  34. // 0-9, and the special characters "_-.".
  35. ID string
  36. // Destination is the export destination. See
  37. // https://cloud.google.com/logging/docs/api/tasks/exporting-logs.
  38. // Examples: "storage.googleapis.com/a-bucket",
  39. // "bigquery.googleapis.com/projects/a-project-id/datasets/a-dataset".
  40. Destination string
  41. // Filter optionally specifies an advanced logs filter (see
  42. // https://cloud.google.com/logging/docs/view/advanced_filters) that
  43. // defines the log entries to be exported. Example: "logName:syslog AND
  44. // severity>=ERROR". If omitted, all entries are returned.
  45. Filter string
  46. }
  47. // CreateSink creates a Sink. It returns an error if the Sink already exists.
  48. // Requires AdminScope.
  49. func (c *Client) CreateSink(ctx context.Context, sink *Sink) (*Sink, error) {
  50. ls, err := c.sClient.CreateSink(ctx, &logpb.CreateSinkRequest{
  51. Parent: c.parent,
  52. Sink: toLogSink(sink),
  53. })
  54. if err != nil {
  55. fmt.Printf("Sink: %+v\n", toLogSink(sink))
  56. return nil, err
  57. }
  58. return fromLogSink(ls), nil
  59. }
  60. // DeleteSink deletes a sink. The provided sinkID is the sink's identifier, such as
  61. // "my-severe-errors-to-pubsub".
  62. // Requires AdminScope.
  63. func (c *Client) DeleteSink(ctx context.Context, sinkID string) error {
  64. return c.sClient.DeleteSink(ctx, &logpb.DeleteSinkRequest{
  65. SinkName: c.sinkPath(sinkID),
  66. })
  67. }
  68. // Sink gets a sink. The provided sinkID is the sink's identifier, such as
  69. // "my-severe-errors-to-pubsub".
  70. // Requires ReadScope or AdminScope.
  71. func (c *Client) Sink(ctx context.Context, sinkID string) (*Sink, error) {
  72. ls, err := c.sClient.GetSink(ctx, &logpb.GetSinkRequest{
  73. SinkName: c.sinkPath(sinkID),
  74. })
  75. if err != nil {
  76. return nil, err
  77. }
  78. return fromLogSink(ls), nil
  79. }
  80. // UpdateSink updates an existing Sink. Requires AdminScope.
  81. func (c *Client) UpdateSink(ctx context.Context, sink *Sink) (*Sink, error) {
  82. ls, err := c.sClient.UpdateSink(ctx, &logpb.UpdateSinkRequest{
  83. SinkName: c.sinkPath(sink.ID),
  84. Sink: toLogSink(sink),
  85. })
  86. if err != nil {
  87. return nil, err
  88. }
  89. return fromLogSink(ls), err
  90. }
  91. func (c *Client) sinkPath(sinkID string) string {
  92. return fmt.Sprintf("%s/sinks/%s", c.parent, sinkID)
  93. }
  94. // Sinks returns a SinkIterator for iterating over all Sinks in the Client's project.
  95. // Requires ReadScope or AdminScope.
  96. func (c *Client) Sinks(ctx context.Context) *SinkIterator {
  97. it := &SinkIterator{
  98. it: c.sClient.ListSinks(ctx, &logpb.ListSinksRequest{Parent: c.parent}),
  99. }
  100. it.pageInfo, it.nextFunc = iterator.NewPageInfo(
  101. it.fetch,
  102. func() int { return len(it.items) },
  103. func() interface{} { b := it.items; it.items = nil; return b })
  104. return it
  105. }
  106. // A SinkIterator iterates over Sinks.
  107. type SinkIterator struct {
  108. it *vkit.LogSinkIterator
  109. pageInfo *iterator.PageInfo
  110. nextFunc func() error
  111. items []*Sink
  112. }
  113. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
  114. func (it *SinkIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
  115. // Next returns the next result. Its second return value is Done if there are
  116. // no more results. Once Next returns Done, all subsequent calls will return
  117. // Done.
  118. func (it *SinkIterator) Next() (*Sink, error) {
  119. if err := it.nextFunc(); err != nil {
  120. return nil, err
  121. }
  122. item := it.items[0]
  123. it.items = it.items[1:]
  124. return item, nil
  125. }
  126. func (it *SinkIterator) fetch(pageSize int, pageToken string) (string, error) {
  127. return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error {
  128. item, err := it.it.Next()
  129. if err != nil {
  130. return err
  131. }
  132. it.items = append(it.items, fromLogSink(item))
  133. return nil
  134. })
  135. }
  136. func toLogSink(s *Sink) *logpb.LogSink {
  137. return &logpb.LogSink{
  138. Name: s.ID,
  139. Destination: s.Destination,
  140. Filter: s.Filter,
  141. OutputVersionFormat: logpb.LogSink_V2,
  142. }
  143. }
  144. func fromLogSink(ls *logpb.LogSink) *Sink {
  145. return &Sink{
  146. ID: ls.Name,
  147. Destination: ls.Destination,
  148. Filter: ls.Filter,
  149. }
  150. }