1// Copyright 2020 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// https://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 15// Code generated by protoc-gen-go_gapic. DO NOT EDIT. 16 17package monitoring 18 19import ( 20 "context" 21 "fmt" 22 "math" 23 "net/url" 24 "time" 25 26 "github.com/golang/protobuf/proto" 27 gax "github.com/googleapis/gax-go/v2" 28 "google.golang.org/api/iterator" 29 "google.golang.org/api/option" 30 gtransport "google.golang.org/api/transport/grpc" 31 metricpb "google.golang.org/genproto/googleapis/api/metric" 32 monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" 33 monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/codes" 36 "google.golang.org/grpc/metadata" 37) 38 39var newMetricClientHook clientHook 40 41// MetricCallOptions contains the retry settings for each method of MetricClient. 42type MetricCallOptions struct { 43 ListMonitoredResourceDescriptors []gax.CallOption 44 GetMonitoredResourceDescriptor []gax.CallOption 45 ListMetricDescriptors []gax.CallOption 46 GetMetricDescriptor []gax.CallOption 47 CreateMetricDescriptor []gax.CallOption 48 DeleteMetricDescriptor []gax.CallOption 49 ListTimeSeries []gax.CallOption 50 CreateTimeSeries []gax.CallOption 51} 52 53func defaultMetricClientOptions() []option.ClientOption { 54 return []option.ClientOption{ 55 option.WithEndpoint("monitoring.googleapis.com:443"), 56 option.WithGRPCDialOption(grpc.WithDisableServiceConfig()), 57 option.WithScopes(DefaultAuthScopes()...), 58 option.WithGRPCDialOption(grpc.WithDefaultCallOptions( 59 grpc.MaxCallRecvMsgSize(math.MaxInt32))), 60 } 61} 62 63func defaultMetricCallOptions() *MetricCallOptions { 64 return &MetricCallOptions{ 65 ListMonitoredResourceDescriptors: []gax.CallOption{ 66 gax.WithRetry(func() gax.Retryer { 67 return gax.OnCodes([]codes.Code{ 68 codes.DeadlineExceeded, 69 codes.Unavailable, 70 }, gax.Backoff{ 71 Initial: 100 * time.Millisecond, 72 Max: 30000 * time.Millisecond, 73 Multiplier: 1.30, 74 }) 75 }), 76 }, 77 GetMonitoredResourceDescriptor: []gax.CallOption{ 78 gax.WithRetry(func() gax.Retryer { 79 return gax.OnCodes([]codes.Code{ 80 codes.DeadlineExceeded, 81 codes.Unavailable, 82 }, gax.Backoff{ 83 Initial: 100 * time.Millisecond, 84 Max: 30000 * time.Millisecond, 85 Multiplier: 1.30, 86 }) 87 }), 88 }, 89 ListMetricDescriptors: []gax.CallOption{ 90 gax.WithRetry(func() gax.Retryer { 91 return gax.OnCodes([]codes.Code{ 92 codes.DeadlineExceeded, 93 codes.Unavailable, 94 }, gax.Backoff{ 95 Initial: 100 * time.Millisecond, 96 Max: 30000 * time.Millisecond, 97 Multiplier: 1.30, 98 }) 99 }), 100 }, 101 GetMetricDescriptor: []gax.CallOption{ 102 gax.WithRetry(func() gax.Retryer { 103 return gax.OnCodes([]codes.Code{ 104 codes.DeadlineExceeded, 105 codes.Unavailable, 106 }, gax.Backoff{ 107 Initial: 100 * time.Millisecond, 108 Max: 30000 * time.Millisecond, 109 Multiplier: 1.30, 110 }) 111 }), 112 }, 113 CreateMetricDescriptor: []gax.CallOption{}, 114 DeleteMetricDescriptor: []gax.CallOption{ 115 gax.WithRetry(func() gax.Retryer { 116 return gax.OnCodes([]codes.Code{ 117 codes.DeadlineExceeded, 118 codes.Unavailable, 119 }, gax.Backoff{ 120 Initial: 100 * time.Millisecond, 121 Max: 30000 * time.Millisecond, 122 Multiplier: 1.30, 123 }) 124 }), 125 }, 126 ListTimeSeries: []gax.CallOption{ 127 gax.WithRetry(func() gax.Retryer { 128 return gax.OnCodes([]codes.Code{ 129 codes.DeadlineExceeded, 130 codes.Unavailable, 131 }, gax.Backoff{ 132 Initial: 100 * time.Millisecond, 133 Max: 30000 * time.Millisecond, 134 Multiplier: 1.30, 135 }) 136 }), 137 }, 138 CreateTimeSeries: []gax.CallOption{}, 139 } 140} 141 142// MetricClient is a client for interacting with Cloud Monitoring API. 143// 144// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. 145type MetricClient struct { 146 // Connection pool of gRPC connections to the service. 147 connPool gtransport.ConnPool 148 149 // The gRPC API client. 150 metricClient monitoringpb.MetricServiceClient 151 152 // The call options for this service. 153 CallOptions *MetricCallOptions 154 155 // The x-goog-* metadata to be sent with each request. 156 xGoogMetadata metadata.MD 157} 158 159// NewMetricClient creates a new metric service client. 160// 161// Manages metric descriptors, monitored resource descriptors, and 162// time series data. 163func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricClient, error) { 164 clientOpts := defaultMetricClientOptions() 165 166 if newMetricClientHook != nil { 167 hookOpts, err := newMetricClientHook(ctx, clientHookParams{}) 168 if err != nil { 169 return nil, err 170 } 171 clientOpts = append(clientOpts, hookOpts...) 172 } 173 174 connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...) 175 if err != nil { 176 return nil, err 177 } 178 c := &MetricClient{ 179 connPool: connPool, 180 CallOptions: defaultMetricCallOptions(), 181 182 metricClient: monitoringpb.NewMetricServiceClient(connPool), 183 } 184 c.setGoogleClientInfo() 185 186 return c, nil 187} 188 189// Connection returns a connection to the API service. 190// 191// Deprecated. 192func (c *MetricClient) Connection() *grpc.ClientConn { 193 return c.connPool.Conn() 194} 195 196// Close closes the connection to the API service. The user should invoke this when 197// the client is no longer required. 198func (c *MetricClient) Close() error { 199 return c.connPool.Close() 200} 201 202// setGoogleClientInfo sets the name and version of the application in 203// the `x-goog-api-client` header passed on each request. Intended for 204// use by Google-written clients. 205func (c *MetricClient) setGoogleClientInfo(keyval ...string) { 206 kv := append([]string{"gl-go", versionGo()}, keyval...) 207 kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) 208 c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) 209} 210 211// ListMonitoredResourceDescriptors lists monitored resource descriptors that match a filter. This method does not require a Workspace. 212func (c *MetricClient) ListMonitoredResourceDescriptors(ctx context.Context, req *monitoringpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator { 213 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 214 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 215 opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...) 216 it := &MonitoredResourceDescriptorIterator{} 217 req = proto.Clone(req).(*monitoringpb.ListMonitoredResourceDescriptorsRequest) 218 it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) { 219 var resp *monitoringpb.ListMonitoredResourceDescriptorsResponse 220 req.PageToken = pageToken 221 if pageSize > math.MaxInt32 { 222 req.PageSize = math.MaxInt32 223 } else { 224 req.PageSize = int32(pageSize) 225 } 226 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 227 var err error 228 resp, err = c.metricClient.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...) 229 return err 230 }, opts...) 231 if err != nil { 232 return nil, "", err 233 } 234 235 it.Response = resp 236 return resp.ResourceDescriptors, resp.NextPageToken, nil 237 } 238 fetch := func(pageSize int, pageToken string) (string, error) { 239 items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) 240 if err != nil { 241 return "", err 242 } 243 it.items = append(it.items, items...) 244 return nextPageToken, nil 245 } 246 it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) 247 it.pageInfo.MaxSize = int(req.PageSize) 248 it.pageInfo.Token = req.PageToken 249 return it 250} 251 252// GetMonitoredResourceDescriptor gets a single monitored resource descriptor. This method does not require a Workspace. 253func (c *MetricClient) GetMonitoredResourceDescriptor(ctx context.Context, req *monitoringpb.GetMonitoredResourceDescriptorRequest, opts ...gax.CallOption) (*monitoredrespb.MonitoredResourceDescriptor, error) { 254 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 255 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 256 opts = append(c.CallOptions.GetMonitoredResourceDescriptor[0:len(c.CallOptions.GetMonitoredResourceDescriptor):len(c.CallOptions.GetMonitoredResourceDescriptor)], opts...) 257 var resp *monitoredrespb.MonitoredResourceDescriptor 258 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 259 var err error 260 resp, err = c.metricClient.GetMonitoredResourceDescriptor(ctx, req, settings.GRPC...) 261 return err 262 }, opts...) 263 if err != nil { 264 return nil, err 265 } 266 return resp, nil 267} 268 269// ListMetricDescriptors lists metric descriptors that match a filter. This method does not require a Workspace. 270func (c *MetricClient) ListMetricDescriptors(ctx context.Context, req *monitoringpb.ListMetricDescriptorsRequest, opts ...gax.CallOption) *MetricDescriptorIterator { 271 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 272 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 273 opts = append(c.CallOptions.ListMetricDescriptors[0:len(c.CallOptions.ListMetricDescriptors):len(c.CallOptions.ListMetricDescriptors)], opts...) 274 it := &MetricDescriptorIterator{} 275 req = proto.Clone(req).(*monitoringpb.ListMetricDescriptorsRequest) 276 it.InternalFetch = func(pageSize int, pageToken string) ([]*metricpb.MetricDescriptor, string, error) { 277 var resp *monitoringpb.ListMetricDescriptorsResponse 278 req.PageToken = pageToken 279 if pageSize > math.MaxInt32 { 280 req.PageSize = math.MaxInt32 281 } else { 282 req.PageSize = int32(pageSize) 283 } 284 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 285 var err error 286 resp, err = c.metricClient.ListMetricDescriptors(ctx, req, settings.GRPC...) 287 return err 288 }, opts...) 289 if err != nil { 290 return nil, "", err 291 } 292 293 it.Response = resp 294 return resp.MetricDescriptors, resp.NextPageToken, nil 295 } 296 fetch := func(pageSize int, pageToken string) (string, error) { 297 items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) 298 if err != nil { 299 return "", err 300 } 301 it.items = append(it.items, items...) 302 return nextPageToken, nil 303 } 304 it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) 305 it.pageInfo.MaxSize = int(req.PageSize) 306 it.pageInfo.Token = req.PageToken 307 return it 308} 309 310// GetMetricDescriptor gets a single metric descriptor. This method does not require a Workspace. 311func (c *MetricClient) GetMetricDescriptor(ctx context.Context, req *monitoringpb.GetMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) { 312 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 313 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 314 opts = append(c.CallOptions.GetMetricDescriptor[0:len(c.CallOptions.GetMetricDescriptor):len(c.CallOptions.GetMetricDescriptor)], opts...) 315 var resp *metricpb.MetricDescriptor 316 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 317 var err error 318 resp, err = c.metricClient.GetMetricDescriptor(ctx, req, settings.GRPC...) 319 return err 320 }, opts...) 321 if err != nil { 322 return nil, err 323 } 324 return resp, nil 325} 326 327// CreateMetricDescriptor creates a new metric descriptor. 328// User-created metric descriptors define 329// custom metrics (at https://cloud.google.com/monitoring/custom-metrics). 330func (c *MetricClient) CreateMetricDescriptor(ctx context.Context, req *monitoringpb.CreateMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) { 331 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 332 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 333 opts = append(c.CallOptions.CreateMetricDescriptor[0:len(c.CallOptions.CreateMetricDescriptor):len(c.CallOptions.CreateMetricDescriptor)], opts...) 334 var resp *metricpb.MetricDescriptor 335 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 336 var err error 337 resp, err = c.metricClient.CreateMetricDescriptor(ctx, req, settings.GRPC...) 338 return err 339 }, opts...) 340 if err != nil { 341 return nil, err 342 } 343 return resp, nil 344} 345 346// DeleteMetricDescriptor deletes a metric descriptor. Only user-created 347// custom metrics (at https://cloud.google.com/monitoring/custom-metrics) can be 348// deleted. 349func (c *MetricClient) DeleteMetricDescriptor(ctx context.Context, req *monitoringpb.DeleteMetricDescriptorRequest, opts ...gax.CallOption) error { 350 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 351 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 352 opts = append(c.CallOptions.DeleteMetricDescriptor[0:len(c.CallOptions.DeleteMetricDescriptor):len(c.CallOptions.DeleteMetricDescriptor)], opts...) 353 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 354 var err error 355 _, err = c.metricClient.DeleteMetricDescriptor(ctx, req, settings.GRPC...) 356 return err 357 }, opts...) 358 return err 359} 360 361// ListTimeSeries lists time series that match a filter. This method does not require a Workspace. 362func (c *MetricClient) ListTimeSeries(ctx context.Context, req *monitoringpb.ListTimeSeriesRequest, opts ...gax.CallOption) *TimeSeriesIterator { 363 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 364 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 365 opts = append(c.CallOptions.ListTimeSeries[0:len(c.CallOptions.ListTimeSeries):len(c.CallOptions.ListTimeSeries)], opts...) 366 it := &TimeSeriesIterator{} 367 req = proto.Clone(req).(*monitoringpb.ListTimeSeriesRequest) 368 it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.TimeSeries, string, error) { 369 var resp *monitoringpb.ListTimeSeriesResponse 370 req.PageToken = pageToken 371 if pageSize > math.MaxInt32 { 372 req.PageSize = math.MaxInt32 373 } else { 374 req.PageSize = int32(pageSize) 375 } 376 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 377 var err error 378 resp, err = c.metricClient.ListTimeSeries(ctx, req, settings.GRPC...) 379 return err 380 }, opts...) 381 if err != nil { 382 return nil, "", err 383 } 384 385 it.Response = resp 386 return resp.TimeSeries, resp.NextPageToken, nil 387 } 388 fetch := func(pageSize int, pageToken string) (string, error) { 389 items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) 390 if err != nil { 391 return "", err 392 } 393 it.items = append(it.items, items...) 394 return nextPageToken, nil 395 } 396 it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) 397 it.pageInfo.MaxSize = int(req.PageSize) 398 it.pageInfo.Token = req.PageToken 399 return it 400} 401 402// CreateTimeSeries creates or adds data to one or more time series. 403// The response is empty if all time series in the request were written. 404// If any time series could not be written, a corresponding failure message is 405// included in the error response. 406func (c *MetricClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error { 407 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 408 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 409 opts = append(c.CallOptions.CreateTimeSeries[0:len(c.CallOptions.CreateTimeSeries):len(c.CallOptions.CreateTimeSeries)], opts...) 410 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 411 var err error 412 _, err = c.metricClient.CreateTimeSeries(ctx, req, settings.GRPC...) 413 return err 414 }, opts...) 415 return err 416} 417 418// MetricDescriptorIterator manages a stream of *metricpb.MetricDescriptor. 419type MetricDescriptorIterator struct { 420 items []*metricpb.MetricDescriptor 421 pageInfo *iterator.PageInfo 422 nextFunc func() error 423 424 // Response is the raw response for the current page. 425 // It must be cast to the RPC response type. 426 // Calling Next() or InternalFetch() updates this value. 427 Response interface{} 428 429 // InternalFetch is for use by the Google Cloud Libraries only. 430 // It is not part of the stable interface of this package. 431 // 432 // InternalFetch returns results from a single call to the underlying RPC. 433 // The number of results is no greater than pageSize. 434 // If there are no more results, nextPageToken is empty and err is nil. 435 InternalFetch func(pageSize int, pageToken string) (results []*metricpb.MetricDescriptor, nextPageToken string, err error) 436} 437 438// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. 439func (it *MetricDescriptorIterator) PageInfo() *iterator.PageInfo { 440 return it.pageInfo 441} 442 443// Next returns the next result. Its second return value is iterator.Done if there are no more 444// results. Once Next returns Done, all subsequent calls will return Done. 445func (it *MetricDescriptorIterator) Next() (*metricpb.MetricDescriptor, error) { 446 var item *metricpb.MetricDescriptor 447 if err := it.nextFunc(); err != nil { 448 return item, err 449 } 450 item = it.items[0] 451 it.items = it.items[1:] 452 return item, nil 453} 454 455func (it *MetricDescriptorIterator) bufLen() int { 456 return len(it.items) 457} 458 459func (it *MetricDescriptorIterator) takeBuf() interface{} { 460 b := it.items 461 it.items = nil 462 return b 463} 464 465// MonitoredResourceDescriptorIterator manages a stream of *monitoredrespb.MonitoredResourceDescriptor. 466type MonitoredResourceDescriptorIterator struct { 467 items []*monitoredrespb.MonitoredResourceDescriptor 468 pageInfo *iterator.PageInfo 469 nextFunc func() error 470 471 // Response is the raw response for the current page. 472 // It must be cast to the RPC response type. 473 // Calling Next() or InternalFetch() updates this value. 474 Response interface{} 475 476 // InternalFetch is for use by the Google Cloud Libraries only. 477 // It is not part of the stable interface of this package. 478 // 479 // InternalFetch returns results from a single call to the underlying RPC. 480 // The number of results is no greater than pageSize. 481 // If there are no more results, nextPageToken is empty and err is nil. 482 InternalFetch func(pageSize int, pageToken string) (results []*monitoredrespb.MonitoredResourceDescriptor, nextPageToken string, err error) 483} 484 485// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. 486func (it *MonitoredResourceDescriptorIterator) PageInfo() *iterator.PageInfo { 487 return it.pageInfo 488} 489 490// Next returns the next result. Its second return value is iterator.Done if there are no more 491// results. Once Next returns Done, all subsequent calls will return Done. 492func (it *MonitoredResourceDescriptorIterator) Next() (*monitoredrespb.MonitoredResourceDescriptor, error) { 493 var item *monitoredrespb.MonitoredResourceDescriptor 494 if err := it.nextFunc(); err != nil { 495 return item, err 496 } 497 item = it.items[0] 498 it.items = it.items[1:] 499 return item, nil 500} 501 502func (it *MonitoredResourceDescriptorIterator) bufLen() int { 503 return len(it.items) 504} 505 506func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} { 507 b := it.items 508 it.items = nil 509 return b 510} 511 512// TimeSeriesIterator manages a stream of *monitoringpb.TimeSeries. 513type TimeSeriesIterator struct { 514 items []*monitoringpb.TimeSeries 515 pageInfo *iterator.PageInfo 516 nextFunc func() error 517 518 // Response is the raw response for the current page. 519 // It must be cast to the RPC response type. 520 // Calling Next() or InternalFetch() updates this value. 521 Response interface{} 522 523 // InternalFetch is for use by the Google Cloud Libraries only. 524 // It is not part of the stable interface of this package. 525 // 526 // InternalFetch returns results from a single call to the underlying RPC. 527 // The number of results is no greater than pageSize. 528 // If there are no more results, nextPageToken is empty and err is nil. 529 InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.TimeSeries, nextPageToken string, err error) 530} 531 532// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. 533func (it *TimeSeriesIterator) PageInfo() *iterator.PageInfo { 534 return it.pageInfo 535} 536 537// Next returns the next result. Its second return value is iterator.Done if there are no more 538// results. Once Next returns Done, all subsequent calls will return Done. 539func (it *TimeSeriesIterator) Next() (*monitoringpb.TimeSeries, error) { 540 var item *monitoringpb.TimeSeries 541 if err := it.nextFunc(); err != nil { 542 return item, err 543 } 544 item = it.items[0] 545 it.items = it.items[1:] 546 return item, nil 547} 548 549func (it *TimeSeriesIterator) bufLen() int { 550 return len(it.items) 551} 552 553func (it *TimeSeriesIterator) takeBuf() interface{} { 554 b := it.items 555 it.items = nil 556 return b 557} 558