Understanding how to use the Google Stackdriver Logging API
I didn’t have any experience using the Google Stackdriver Logging API [1], other than going through logs in the Logs Viewer tracking down bugs. Recently, the team I am part of worked on displaying error logs in one of Vendasta’s [2] products. To query for logs, I needed to use the Stackdriver Logging API and its Go client library. This blog covers some of the interesting things I found while using the API.
The Go library endpoint we used from the Stackdriver Logging API is ListLogEntries
[3]. It takes a collection of config names like cluster, namespace, and resource IDs. It also takes a page size and a page token. This is how the page size and token are defined in the proto:
This seemed pretty easy. I’d pass them in and API would perform paging. This is what I came up with:
I deployed it and did some testing in Postman [4]. I gave it a small page size and it returned me all the logs, whatever the page size. Why wasn’t pagination working? Do you see the problem in my code above?
I was so confident it was Google API’s issue that I opened an issue in the Github repo of Google’s client library. Later I got this reply:
So here’s the tricky part:
- The actual log fetching doesn’t happen at
ListLogEntries
call.ListLogEntries
simply defines an iterator, as well as the internal functions such asfetch()
, which does the gRPC call to Stackdriver API, andNext()
, which goes and points at the next item or callfetch()
. Then it returns the iterator; - The log fetching happens when
iterator.Next()
is called; - When
Next()
finds out that there are no items left in the current buffer, it'll call Stackdriver API again to get more logs; - If there are no more logs,
iterator.Done
will be returned, which breaks the for-loop; - The
pageSize
we passed in doesn’t control how many logs we’ll get back, It controls the maximum number of items that the go library fetches from Stackdriver API each time.
So what my code was doing is:
This is a problem I encountered that I found very interesting. It is not only ListLogEntries
that works this way; all list methods in the Stackdriver Logging Go library seem to behave the same way. Google has a recommended pattern of using Go iterators [5].
Another tool I found very useful is the API Explorer [6]. It lists all of Google’s APIs and provides an interface where developers can directly interact with them.
References:
- https://cloud.google.com/logging/docs/reference/v2/rest/
- https://www.vendasta.com/
- https://github.com/googleapis/google-cloud-go/blob/5a21f3e59ff498bc7a9c6c61d000b3b23b7fa991/logging/apiv2/logging_client.go#L172
- https://www.getpostman.com/
- https://github.com/googleapis/google-cloud-go/wiki/Iterator-Guidelines
- https://developers.google.com/apis-explorer/#p/