Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LogEntry methods and tests #1110

Merged
merged 1 commit into from
Jul 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package com.google.cloud.logging;

import com.google.cloud.AsyncPage;
import com.google.cloud.MonitoredResource;
import com.google.cloud.MonitoredResourceDescriptor;
import com.google.cloud.Page;
import com.google.cloud.Service;
import com.google.common.collect.ImmutableMap;

import java.util.Map;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -62,6 +64,134 @@ public static ListOption pageToken(String pageToken) {
}
}

/**
* Class for specifying options for writing log entries.
*/
final class WriteOption extends Option {

private static final long serialVersionUID = 715900132268584612L;

enum OptionType implements Option.OptionType {
LOG_NAME, RESOURCE, LABELS;

@SuppressWarnings("unchecked")
<T> T get(Map<Option.OptionType, ?> options) {
return (T) options.get(this);
}
}

private WriteOption(OptionType option, Object value) {
super(option, value);
}

/**
* Returns an option to specify a default log name (see {@link LogEntry#logName()}) for those
* log entries that do not specify their own log name. Example: {@code syslog}.
*/
public static WriteOption logName(String logName) {
return new WriteOption(OptionType.LOG_NAME, logName);
}

/**
* Returns an option to specify a default monitored resource (see {@link LogEntry#resource()})
* for those log entries that do not specify their own resource.
*/
public static WriteOption resource(MonitoredResource resource) {
return new WriteOption(OptionType.RESOURCE, resource);
}

/**
* Sets an option to specify (key, value) pairs that are added to the {@link LogEntry#labels()}
* of each log entry written, except when a log entry already has a value associated to the
* same key.
*/
public static WriteOption labels(Map<String, String> labels) {
return new WriteOption(OptionType.LABELS, ImmutableMap.copyOf(labels));
}
}

/**
* Fields according to which log entries can be sorted.
*/
enum SortingField {
TIMESTAMP;

String selector() {
return name().toLowerCase();
}
}

/**
* Sorting orders available when listing log entries.
*/
enum SortingOrder {
DESCENDING("desc"),
ASCENDING("asc");

private final String selector;

SortingOrder(String selector) {
this.selector = selector;
}

String selector() {
return selector;
}
}

/**
* Class for specifying options for listing log entries.
*/
final class EntryListOption extends Option {

private static final long serialVersionUID = -1561159676386917050L;

enum OptionType implements Option.OptionType {
PAGE_SIZE, PAGE_TOKEN, ORDER_BY, FILTER;

@SuppressWarnings("unchecked")
<T> T get(Map<Option.OptionType, ?> options) {
return (T) options.get(this);
}
}

private EntryListOption(OptionType option, Object value) {
super(option, value);
}

/**
* Returns an option to specify the maximum number of log entries returned per page.
*/
public static EntryListOption pageSize(int pageSize) {
return new EntryListOption(OptionType.PAGE_SIZE, pageSize);
}

/**
* Returns an option to specify the page token from which to start listing log entries.
*/
public static EntryListOption pageToken(String pageToken) {
return new EntryListOption(OptionType.PAGE_TOKEN, pageToken);
}

/**
* Returns an option to sort log entries. If not specified, log entries are sorted in ascending
* (most-recent last) order with respect to the {@link LogEntry#timestamp()} value.
*/
public static EntryListOption sortOrder(SortingField field, SortingOrder order) {
return new EntryListOption(OptionType.ORDER_BY, field.selector() + ' ' + order.selector());
}

/**
* Returns an option to specify a filter to the log entries to be listed.
*
* @see <a href="https://cloud.google.com/logging/docs/view/advanced_filters">Advanced Logs
* Filters</a>
*/
public static EntryListOption filter(String filter) {
return new EntryListOption(OptionType.FILTER, filter);
}
}

/**
* Creates a new sink.
*
Expand Down Expand Up @@ -244,4 +374,49 @@ Future<AsyncPage<MonitoredResourceDescriptor>> listMonitoredResourceDescriptorsA
* if it was not found.
*/
Future<Boolean> deleteMetricAsync(String metric);

/**
* Writes log entries to Cloud Logging. Use {@link WriteOption#logName(String)} to provide a log
* name for those entries that do not specify one. Use
* {@link WriteOption#resource(MonitoredResource)} to provide a monitored resource for those
* entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
* to be added to every entry in {@code logEntries}.
*/
void write(Iterable<LogEntry> logEntries, WriteOption... options);

/**
* Sends a request to log entries to Cloud Logging. Use {@link WriteOption#logName(String)} to
* provide a log name for those entries that do not specify one. Use
* {@link WriteOption#resource(MonitoredResource)} to provide a monitored resource for those
* entries that do not specify one. Use {@link WriteOption#labels(Map)} to provide some labels
* to be added to every entry in {@code logEntries}. The method returns a {@code Future} object
* that can be used to wait for the write operation to be completed.
*/
Future<Void> writeAsync(Iterable<LogEntry> logEntries, WriteOption... options);

/**
* Lists log entries. This method returns a {@link Page} object that can be used to consume
* paginated results. Use {@link EntryListOption#pageSize(int)} to specify the page size. Use
* {@link EntryListOption#pageToken(String)} to specify the page token from which to start listing
* entries. Use {@link EntryListOption#sortOrder(SortingField, SortingOrder)} to sort log entries
* according to your preferred order (default is most-recent last). Use
* {@link EntryListOption#filter(String)} to filter listed log entries.
*
* @throws LoggingException upon failure
*/
Page<LogEntry> listLogEntries(EntryListOption... options);

/**
* Sends a request for listing log entries. This method returns a {@code Future} object to consume
* the result. {@link Future#get()} returns an {@link AsyncPage} object that can be used to
* asynchronously handle paginated results. Use {@link EntryListOption#pageSize(int)} to specify
* the page size. Use {@link EntryListOption#pageToken(String)} to specify the page token from
* which to start listing entries. Use
* {@link EntryListOption#sortOrder(SortingField, SortingOrder)} to sort log entries according to
* your preferred order (default is most-recent last). Use {@link EntryListOption#filter(String)}
* to filter listed log entries.
*
* @throws LoggingException upon failure
*/
Future<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... options);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
package com.google.cloud.logging;

import static com.google.api.client.util.Preconditions.checkArgument;
import static com.google.cloud.logging.Logging.EntryListOption.OptionType.FILTER;
import static com.google.cloud.logging.Logging.EntryListOption.OptionType.ORDER_BY;
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_SIZE;
import static com.google.cloud.logging.Logging.ListOption.OptionType.PAGE_TOKEN;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LABELS;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.LOG_NAME;
import static com.google.cloud.logging.Logging.WriteOption.OptionType.RESOURCE;
import static com.google.common.util.concurrent.Futures.lazyTransform;

import com.google.cloud.AsyncPage;
import com.google.cloud.AsyncPageImpl;
import com.google.cloud.BaseService;
import com.google.cloud.MonitoredResource;
import com.google.cloud.MonitoredResourceDescriptor;
import com.google.cloud.Page;
import com.google.cloud.PageImpl;
Expand All @@ -34,6 +40,7 @@
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Uninterruptibles;
Expand All @@ -44,6 +51,8 @@
import com.google.logging.v2.DeleteSinkRequest;
import com.google.logging.v2.GetLogMetricRequest;
import com.google.logging.v2.GetSinkRequest;
import com.google.logging.v2.ListLogEntriesRequest;
import com.google.logging.v2.ListLogEntriesResponse;
import com.google.logging.v2.ListLogMetricsRequest;
import com.google.logging.v2.ListLogMetricsResponse;
import com.google.logging.v2.ListMonitoredResourceDescriptorsRequest;
Expand All @@ -52,6 +61,8 @@
import com.google.logging.v2.ListSinksResponse;
import com.google.logging.v2.UpdateLogMetricRequest;
import com.google.logging.v2.UpdateSinkRequest;
import com.google.logging.v2.WriteLogEntriesRequest;
import com.google.logging.v2.WriteLogEntriesResponse;
import com.google.protobuf.Empty;

import java.util.List;
Expand All @@ -71,6 +82,13 @@ public Boolean apply(Empty input) {
return input != null;
}
};
private static final Function<WriteLogEntriesResponse, Void> WRITE_RESPONSE_TO_VOID_FUNCTION =
new Function<WriteLogEntriesResponse, Void>() {
@Override
public Void apply(WriteLogEntriesResponse input) {
return null;
}
};

LoggingImpl(LoggingOptions options) {
super(options);
Expand Down Expand Up @@ -154,6 +172,21 @@ public Future<AsyncPage<Metric>> nextPage() {
}
}

private static class LogEntryPageFetcher extends BasePageFetcher<LogEntry> {

private static final long serialVersionUID = 4001239712280747734L;

LogEntryPageFetcher(LoggingOptions serviceOptions, String cursor,
Map<Option.OptionType, ?> requestOptions) {
super(serviceOptions, cursor, requestOptions);
}

@Override
public Future<AsyncPage<LogEntry>> nextPage() {
return listLogEntriesAsync(serviceOptions(), requestOptions());
}
}

@Override
public Sink create(SinkInfo sink) {
return get(createAsync(sink));
Expand Down Expand Up @@ -408,6 +441,87 @@ public Future<Boolean> deleteMetricAsync(String metric) {
return lazyTransform(rpc.delete(request), EMPTY_TO_BOOLEAN_FUNCTION);
}

private static WriteLogEntriesRequest writeLogEntriesRequest(LoggingOptions serviceOptions,
Iterable<LogEntry> logEntries, Map<Option.OptionType, ?> options) {
String projectId = serviceOptions.projectId();
WriteLogEntriesRequest.Builder builder = WriteLogEntriesRequest.newBuilder();
String logName = LOG_NAME.get(options);
if (logName != null) {
builder.setLogName(LoggingServiceV2Api.formatLogName(projectId, logName));
}
MonitoredResource resource = RESOURCE.get(options);
if (resource != null) {
builder.setResource(resource.toPb());
}
Map<String, String> labels = LABELS.get(options);
if (labels != null) {
builder.putAllLabels(labels);
}
builder.addAllEntries(Iterables.transform(logEntries, LogEntry.toPbFunction(projectId)));
return builder.build();
}

public void write(Iterable<LogEntry> logEntries, WriteOption... options) {
get(writeAsync(logEntries, options));
}

public Future<Void> writeAsync(Iterable<LogEntry> logEntries, WriteOption... options) {
return lazyTransform(
rpc.write(writeLogEntriesRequest(options(), logEntries, optionMap(options))),
WRITE_RESPONSE_TO_VOID_FUNCTION);
}

private static ListLogEntriesRequest listLogEntriesRequest(LoggingOptions serviceOptions,
Map<Option.OptionType, ?> options) {
ListLogEntriesRequest.Builder builder = ListLogEntriesRequest.newBuilder();
builder.addProjectIds(serviceOptions.projectId());
Integer pageSize = PAGE_SIZE.get(options);
if (pageSize != null) {
builder.setPageSize(pageSize);
}
String pageToken = PAGE_TOKEN.get(options);
if (pageToken != null) {
builder.setPageToken(pageToken);
}
String orderBy = ORDER_BY.get(options);
if (orderBy != null) {
builder.setOrderBy(orderBy);
}
String filter = FILTER.get(options);
if (filter != null) {
builder.setFilter(filter);
}
return builder.build();
}

private static Future<AsyncPage<LogEntry>> listLogEntriesAsync(
final LoggingOptions serviceOptions, final Map<Option.OptionType, ?> options) {
final ListLogEntriesRequest request = listLogEntriesRequest(serviceOptions, options);
Future<ListLogEntriesResponse> list = serviceOptions.rpc().list(request);
return lazyTransform(list, new Function<ListLogEntriesResponse, AsyncPage<LogEntry>>() {
@Override
public AsyncPage<LogEntry> apply(ListLogEntriesResponse listLogEntrysResponse) {
List<LogEntry> entries = listLogEntrysResponse.getEntriesList() == null
? ImmutableList.<LogEntry>of() : Lists.transform(listLogEntrysResponse.getEntriesList(),
LogEntry.FROM_PB_FUNCTION);
String cursor = listLogEntrysResponse.getNextPageToken().equals("") ? null
: listLogEntrysResponse.getNextPageToken();
return new AsyncPageImpl<>(new LogEntryPageFetcher(serviceOptions, cursor, options), cursor,
entries);
}
});
}

@Override
public Page<LogEntry> listLogEntries(EntryListOption... options) {
return get(listLogEntriesAsync(options));
}

@Override
public Future<AsyncPage<LogEntry>> listLogEntriesAsync(EntryListOption... options) {
return listLogEntriesAsync(options(), optionMap(options));
}

@Override
public void close() throws Exception {
if (closed) {
Expand Down
Loading