App Engine Java SDK version 1.9.14
[gae.git] / java / src / main / com / google / appengine / api / log / LogQuery.java
blob746a4fb7068c0fd73b9465e720a7288b6066dde3
1 // Copyright 2011 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.log;
5 import com.google.appengine.api.log.LogService.LogLevel;
6 import com.google.common.collect.ImmutableList;
8 import java.io.Serializable;
9 import java.util.ArrayList;
10 import java.util.Comparator;
11 import java.util.HashSet;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
17 /**
18 * Allows users to customize the behavior of {@link LogService#fetch(LogQuery)}.
19 * <p>
20 * {@code startTime} is the earliest request completion or last-update time
21 * that results should be fetched for, in seconds since the Unix epoch. If
22 * {@code null} then no requests will be excluded for ending too long ago.
23 * <p>
24 * {@code endTime} is the latest request completion or last-update time that
25 * results should be fetched for, in seconds since the Unix epoch. If
26 * {@code null} then no requests will be excluded for ending too recently.
27 * <p>
28 * {@code offset} is a cursor into the log stream retrieved from a previously
29 * emitted {@link RequestLogs#getOffset}. This iterator will begin returning
30 * logs immediately after the record from which the offset came. If
31 * {@code null}, the query will begin at {@code startTime}.
32 * <p>
33 * {@code minLogLevel} is a {@link LogService.LogLevel} which serves as a
34 * filter on the requests returned. Requests with no application logs at or
35 * above the specified level will be omitted. Works even if
36 * {@code includeAppLogs} is not True.
37 * <p>
38 * {@code includeIncomplete} selects whether requests that have started but not
39 * yet finished should be included in the query. Defaults to False.
40 * <p>
41 * {@code includeAppLogs} specifies whether or not to include application logs
42 * in the query results. Defaults to False.
43 * <p>
44 * {@code majorVersionIds} specifies versions of the application's default
45 * module for which logs records should retrieved.
46 * <p>
47 * {@code versions} specifies module versions of the application for which
48 * logs should be retrieved.
49 * <p>
50 * {@code requestIds}, if not {@code empty()}, indicates that instead of a
51 * time-based scan, logs for the specified requests should be returned.
52 * See the Request IDs section of <a
53 * href="https://developers.google.com/appengine/docs/java/runtime#The_Environment}">
54 * the Java Servlet Environment documentation</a> for how to retrieve these IDs
55 * at runtime. Malformed request IDs cause an exception and unrecognized request IDs
56 * are ignored. This option may not be combined with other filtering options such as
57 * startTime, endTime, offset, or minLogLevel. When {@code requestIds} is not {@code empty()},
58 * {@code majorVersionIds} are ignored. Logs are returned in the order requested.
59 * <p>
60 * {@code batchSize} specifies the internal batching strategy of the returned
61 * {@link java.lang.Iterable Iterable&lt;RequestLogs&gt;}. Has no impact on the
62 * result of the query.
63 * <p>
64 * Notes on usage:<br>
65 * The recommended way to instantiate a {@code LogQuery} object is to
66 * statically import {@link Builder}.* and invoke a static
67 * creation method followed by an instance mutator (if needed):
69 * <pre>
70 * import static com.google.appengine.api.log.LogQuery.Builder.*;
72 * ...
74 * // All requests, including application logs.
75 * iter = logService.fetch(withIncludeAppLogs(true));
77 * // All requests ending in the past day (or still running) with an info log or higher.
78 * Calendar cal = Calendar.getInstance();
79 * cal.add(Calendar.DAY_OF_MONTH, -1);
80 * iter = logService.fetch(withEndTimeMillis(cal.time())
81 * .includeIncomplete(true).minimumLogLevel(LogService.INFO));
82 * </pre>
84 * There are a couple of ways to configure {@link LogQuery} to limit
85 * {@link LogService#fetch(LogQuery)} to only return log records for specific
86 * module versions.
87 * <ol>
88 * <li><b>{@link #versions(List)}({@link Builder#withVersions(List)})</b> -
89 * Includes designated module versions for the application.
90 * <li><b>{@link #majorVersionIds(List)} ({@link Builder#withMajorVersionIds(List)})</b> -
91 * Includes designated versions of the default module for the application.
92 * </ol>
93 * For a particular {@link LogQuery} only one of these methods may be used. If neither is used,
94 * {@link LogService#fetch(LogQuery)} results may include any module version.
96 * It is not allowed to call both {@link #versions(List)} ({@link Builder#withVersions(List)})
97 * and {@link #requestIds(List)}({@link Builder#withRequestIds(List)} for the same {@link LogQuery}.
100 public final class LogQuery implements Cloneable, Serializable {
101 private static final long serialVersionUID = 3660093076203855168L;
102 static final Comparator<Version> VERSION_COMPARATOR = new VersionComparator();
104 private String offset;
106 private Long startTimeUsec;
108 private Long endTimeUsec;
110 private int batchSize = LogService.DEFAULT_ITEMS_PER_FETCH;
112 private LogLevel minLogLevel;
113 private boolean includeIncomplete = false;
114 private boolean includeAppLogs = false;
115 private List<String> majorVersionIds = new ArrayList<String>();
116 private List<Version> versions = new ArrayList<Version>();
118 private List<String> requestIds = new ArrayList<String>();
120 private static final String MAJOR_VERSION_ID_REGEX = "[a-z\\d][a-z\\d\\-]{0,99}";
121 private static final Pattern VERSION_PATTERN = Pattern.compile(MAJOR_VERSION_ID_REGEX);
122 private static final String REQUEST_ID_REGEX = "\\A\\p{XDigit}+\\z";
123 private static final Pattern REQUEST_ID_PATTERN = Pattern.compile(REQUEST_ID_REGEX);
126 * Specifies a version of a module.
128 public static final class Version implements Serializable {
129 private static final long serialVersionUID = 3697597908142270764L;
130 private static final String INVALID_MODULE_ID_MESSAGE_TEMPLATE = "Invalid module id '%s'";
131 private static final String INVALID_VERSION_ID_MESSAGE_TEMPLATE = "Invalid version id '%s'";
132 private final String moduleId;
133 private final String versionId;
136 * Constructs a {@link Version}.
137 * @param moduleId A valid module id.
138 * @param versionId A valid version id.
140 public Version(String moduleId, String versionId) {
141 this.moduleId = verifyId(moduleId, INVALID_MODULE_ID_MESSAGE_TEMPLATE);
142 this.versionId = verifyId(versionId, INVALID_VERSION_ID_MESSAGE_TEMPLATE);
146 * Returns the moduleId.
148 public String getModuleId() {
149 return moduleId;
153 * Returns the version id.
155 public String getVersionId() {
156 return versionId;
159 @Override
160 public int hashCode() {
161 final int prime = 31;
162 int result = 1;
163 result = prime * result + ((moduleId == null) ? 0 : moduleId.hashCode());
164 result = prime * result + ((versionId == null) ? 0 : versionId.hashCode());
165 return result;
168 @Override
169 public boolean equals(Object obj) {
170 if (this == obj) {
171 return true;
173 if (obj == null) {
174 return false;
176 if (getClass() != obj.getClass()) {
177 return false;
179 Version other = (Version) obj;
180 if (moduleId == null) {
181 if (other.moduleId != null) {
182 return false;
184 } else if (!moduleId.equals(other.moduleId)) {
185 return false;
188 if (versionId == null) {
189 if (other.versionId != null) {
190 return false;
192 } else if (!versionId.equals(other.versionId)) {
193 return false;
195 return true;
198 @Override
199 public String toString() {
200 return "Version: moduleId=" + moduleId + " versionId=" + versionId;
204 * Verifies and returns a module id or version id.
206 * Note this verification uses the VERSION_PATTERN regular expression which will catch
207 * many but not all syntactic errors.
209 * @param moduleOrVersionId The module or version id to verify.
210 * @param messageTemplate A message template with a placeholder for the invalid value.
211 * @return moduleOrVersionId
212 * @throws IllegalArgumentException if moduleOrVersionId is not valid.
214 private static String verifyId(String moduleOrVersionId, String messageTemplate) {
215 Matcher matcher = VERSION_PATTERN.matcher(moduleOrVersionId);
216 if (!matcher.matches()) {
217 throw new IllegalArgumentException(String.format(messageTemplate, moduleOrVersionId));
219 return moduleOrVersionId;
224 * Compares {@link Version} values by {@link Version#getModuleId()} and
225 * breaks ties by comparing by {@link Version#getVersionId()}
227 private static class VersionComparator implements Comparator<Version> {
228 @Override
229 public int compare(Version version1, Version version2) {
230 int result = version1.getModuleId().compareTo(version2.getModuleId());
231 if (result == 0) {
232 result = version1.getVersionId().compareTo(version2.getVersionId());
234 return result;
239 * Contains static creation methods for {@link LogQuery}.
241 public static final class Builder {
243 * Create a {@link LogQuery} with the given offset.
244 * Shorthand for <code>LogQuery.Builder.withDefaults().offset(offset);</code>.
245 * Please read the {@link LogQuery} class javadoc for an explanation of
246 * how offsets are used.
247 * @param offset the offset to use.
248 * @return The newly created LogQuery instance.
250 public static LogQuery withOffset(String offset) {
251 return withDefaults().offset(offset);
255 * Create a {@link LogQuery} with the given start time.
256 * Shorthand for <code>LogQuery.Builder.withDefaults().startTimeMillis(startTimeMillis);</code>.
257 * Please read the {@link LogQuery} class javadoc for an explanation of
258 * how start time is used.
259 * @param startTimeMillis the start time to use, in milliseconds.
260 * @return The newly created LogQuery instance.
262 public static LogQuery withStartTimeMillis(long startTimeMillis) {
263 return withDefaults().startTimeMillis(startTimeMillis);
267 * Create a {@link LogQuery} with the given start time.
268 * Shorthand for <code>LogQuery.Builder.withDefaults().startTimeUsec(startTimeUsec);</code>.
269 * Please read the {@link LogQuery} class javadoc for an explanation of
270 * how start time is used.
271 * @param startTimeUsec the start time to use, in microseconds.
272 * @return The newly created LogQuery instance.
274 public static LogQuery withStartTimeUsec(long startTimeUsec) {
275 return withDefaults().startTimeUsec(startTimeUsec);
279 * Create a {@link LogQuery} with the given end time.
280 * Shorthand for <code>LogQuery.Builder.withDefaults().endTimeMillis(endTimeMillis);</code>.
281 * Please read the {@link LogQuery} class javadoc for an explanation of
282 * how end time is used.
283 * @param endTimeMillis the start time to use, in milliseconds.
284 * @return The newly created LogQuery instance.
286 public static LogQuery withEndTimeMillis(long endTimeMillis) {
287 return withDefaults().endTimeMillis(endTimeMillis);
291 * Create a {@link LogQuery} with the given end time.
292 * Shorthand for <code>LogQuery.Builder.withDefaults().endTimeUsec(endTimeUsec);</code>.
293 * Please read the {@link LogQuery} class javadoc for an explanation of
294 * how end time is used.
295 * @param endTimeUsec the start time to use, in microseconds.
296 * @return The newly created LogQuery instance.
298 public static LogQuery withEndTimeUsec(long endTimeUsec) {
299 return withDefaults().endTimeUsec(endTimeUsec);
303 * Create a {@link LogQuery} with the given batch size.
304 * Shorthand for <code>LogQuery.Builder.withDefaults().batchSize(batchSize);</code>.
305 * Please read the {@link LogQuery} class javadoc for an explanation of
306 * how batch size is used.
307 * @param batchSize the batch size to set.
308 * @return The newly created LogQuery instance.
310 public static LogQuery withBatchSize(int batchSize) {
311 return withDefaults().batchSize(batchSize);
315 * Create a {@link LogQuery} with the given minimum log level.
316 * Shorthand for <code>LogQuery.Builder.withDefaults().minLogLevel(minLogLevel);</code>.
317 * Please read the {@link LogQuery} class javadoc for an explanation of
318 * how minimum log level is used.
319 * @param minLogLevel the minimum log level to set.
320 * @return The newly created LogQuery instance.
322 public static LogQuery withMinLogLevel(LogLevel minLogLevel) {
323 return withDefaults().minLogLevel(minLogLevel);
327 * Create a {@link LogQuery} with the given include incomplete setting.
328 * Shorthand for
329 * <code>LogQuery.Builder.withDefaults().includeIncomplete(includeIncomplete);</code>.
330 * Please read the {@link LogQuery} class javadoc for an explanation of
331 * how include incomplete is used.
332 * @param includeIncomplete the inclusion value to set.
333 * @return The newly created LogQuery instance.
335 public static LogQuery withIncludeIncomplete(boolean includeIncomplete) {
336 return withDefaults().includeIncomplete(includeIncomplete);
340 * Create a {@link LogQuery} with include application logs set.
341 * Shorthand for <code>LogQuery.Builder.withDefaults().includeAppLogs(includeAppLogs);</code>.
342 * Please read the {@link LogQuery} class javadoc for an explanation of
343 * the include application logs setting.
344 * @param includeAppLogs the inclusion value to set.
345 * @return The newly created LogQuery instance.
347 public static LogQuery withIncludeAppLogs(boolean includeAppLogs) {
348 return withDefaults().includeAppLogs(includeAppLogs);
352 * Create a {@link LogQuery} with the given major version IDs.
353 * Shorthand for <code>LogQuery.Builder.withDefaults().majorVersionIds(versionIds);</code>.
354 * Please read the {@link LogQuery} class javadoc for an explanation of
355 * how the list of major version ids is used.
356 * @param versionIds the major version id list to set.
357 * @return The newly created LogQuery instance.
359 public static LogQuery withMajorVersionIds(List<String> versionIds) {
360 return withDefaults().majorVersionIds(versionIds);
364 * Create a {@link LogQuery} with the given {@link Version} values.
365 * Shorthand for
366 * <code>LogQuery.Builder.withDefaults().versions(versions);</code>.
367 * Please read the {@link LogQuery} class javadoc for usage information.
368 * @param versions the list to set.
369 * @return The newly created LogQuery instance.
371 public static LogQuery withVersions(List<Version> versions) {
372 return withDefaults().versions(versions);
376 * Create a {@link LogQuery} with the given request IDs.
377 * Shorthand for <code>LogQuery.Builder.withDefaults().requestIds(requestIds);</code>.
378 * See the {@link LogQuery} class javadoc for an explanation of
379 * how the list of request ids is used.
380 * @param requestIds the request id list to set.
381 * @return The newly created LogQuery instance.
382 * @since App Engine 1.7.4.
384 public static LogQuery withRequestIds(List<String> requestIds) {
385 return withDefaults().requestIds(requestIds);
389 * Helper method for creating a {@link LogQuery} instance with
390 * default values. Please read the {@link LogQuery} class javadoc for an
391 * explanation of the defaults.
393 public static LogQuery withDefaults() {
394 return new LogQuery();
399 * Makes a copy of a provided LogQuery.
401 * @return A new LogQuery whose fields are copied from the given LogQuery.
403 @Override
404 public LogQuery clone() {
405 LogQuery clone;
406 try {
407 clone = (LogQuery) super.clone();
408 } catch (CloneNotSupportedException e) {
409 throw new RuntimeException(e);
412 clone.majorVersionIds = new ArrayList<String>(majorVersionIds);
413 clone.requestIds = new ArrayList<String>(requestIds);
414 clone.versions = new ArrayList<Version>(versions);
415 return clone;
419 * Sets the offset. Please read the class javadoc for an explanation of
420 * how offset is used.
421 * @param offset The offset to set.
422 * @return {@code this} (for chaining)
424 public LogQuery offset(String offset) {
425 this.offset = offset;
426 return this;
430 * Sets the start time to a value in milliseconds. Please read the class
431 * javadoc for an explanation of how start time is used.
432 * @param startTimeMillis The start time to set, in milliseconds.
433 * @return {@code this} (for chaining)
435 public LogQuery startTimeMillis(long startTimeMillis) {
436 this.startTimeUsec = startTimeMillis * 1000;
437 return this;
441 * Sets the start time to a value in microseconds. Please read the class
442 * javadoc for an explanation of how start time is used.
443 * @param startTimeUsec The start time to set, in microseconds.
444 * @return {@code this} (for chaining)
446 public LogQuery startTimeUsec(long startTimeUsec) {
447 this.startTimeUsec = startTimeUsec;
448 return this;
452 * Sets the end time to a value in milliseconds. Please read the class
453 * javadoc for an explanation of how end time is used.
454 * @param endTimeMillis The end time to set, in milliseconds.
455 * @return {@code this} (for chaining)
457 public LogQuery endTimeMillis(long endTimeMillis) {
458 this.endTimeUsec = endTimeMillis * 1000;
459 return this;
463 * Sets the end time to a value in microseconds. Please read the class
464 * javadoc for an explanation of how end time is used.
465 * @param endTimeUsec The end time to set, in microseconds.
466 * @return {@code this} (for chaining)
468 public LogQuery endTimeUsec(long endTimeUsec) {
469 this.endTimeUsec = endTimeUsec;
470 return this;
474 * Sets the batch size. Please read the class javadoc for an explanation of
475 * how batch size is used.
476 * @param batchSize The batch size to set. Must be greater than 0.
477 * @return {@code this} (for chaining)
479 public LogQuery batchSize(int batchSize) {
480 if (batchSize < 1) {
481 throw new IllegalArgumentException("batchSize must be greater than zero");
484 this.batchSize = batchSize;
485 return this;
489 * Sets the minimum log level. Please read the class javadoc for an
490 * explanation of how minimum log level is used.
491 * @param minLogLevel The minimum log level to set.
492 * @return {@code this} (for chaining)
494 public LogQuery minLogLevel(LogLevel minLogLevel) {
495 this.minLogLevel = minLogLevel;
496 return this;
500 * Sets include incomplete. Please read the class javadoc for an
501 * explanation of how include incomplete is used.
502 * @param includeIncomplete The value to set.
503 * @return {@code this} (for chaining)
505 public LogQuery includeIncomplete(boolean includeIncomplete) {
506 this.includeIncomplete = includeIncomplete;
507 return this;
511 * Sets include application logs. Please read the class javadoc for an
512 * explanation of how include application logs is used.
513 * @param includeAppLogs The value to set.
514 * @return {@code this} (for chaining)
516 public LogQuery includeAppLogs(boolean includeAppLogs) {
517 this.includeAppLogs = includeAppLogs;
518 return this;
522 * Sets the major version identifiers to query. Please read the class
523 * javadoc for an explanation of how major versions are used.
524 * @param versionIds The major version identifier list to set.
525 * @return {@code this} (for chaining)
527 public LogQuery majorVersionIds(List<String> versionIds) {
528 if (!versions.isEmpty()) {
529 throw new IllegalStateException(
530 "LogQuery.majorVersionIds may not be called after LogQuery.versions.");
533 for (String versionId : versionIds) {
534 Matcher matcher = VERSION_PATTERN.matcher(versionId);
535 if (!matcher.matches()) {
536 throw new IllegalArgumentException("versionIds must only contain valid " +
537 "major version identifiers. Version " + versionId + " is not a valid " +
538 "major version identifier.");
542 this.majorVersionIds = versionIds;
543 return this;
547 * Restricts the query to log records for the specified module versions.
549 * Please read the class javadoc for usage information.
551 * @param versions The list of module versions to query.
552 * @return {@code this} (for chaining)
554 public LogQuery versions(List<Version> versions) {
555 if (!this.majorVersionIds.isEmpty()) {
556 throw new IllegalStateException(
557 "LogQuery.versions may not be called after LogQuery.majorVersionIds.");
560 if (!requestIds.isEmpty()) {
561 throw new IllegalStateException(
562 "LogQuery.versions may not be called after LogQuery.requestIds.");
565 this.versions.clear();
566 this.versions.addAll(versions);
567 return this;
571 * Sets the list of request ids to query. See the class javadoc for an
572 * explanation of how request ids are used.
573 * @param requestIds The request id list to set.
574 * @return {@code this} (for chaining)
576 public LogQuery requestIds(List<String> requestIds) {
577 if (!versions.isEmpty()) {
578 throw new IllegalStateException(
579 "LogQuery.requestIds may not be called after LogQuery.versions.");
582 Set<String> seen = new HashSet<String>();
583 for (String requestId : requestIds) {
584 if (!seen.add(requestId)) {
585 throw new IllegalArgumentException("requestIds must be unique.");
588 Matcher matcher = REQUEST_ID_PATTERN.matcher(requestId);
589 if (!matcher.matches()) {
590 throw new IllegalArgumentException("requestIds must only contain valid " +
591 "request ids. " + requestId + " is not a valid " +
592 "request id.");
596 this.requestIds = requestIds;
597 return this;
601 * @return The offset, or {@code null} if none was provided.
603 public String getOffset() {
604 return offset;
608 * @return The batch size, or {@code null} if none was provided.
610 public Integer getBatchSize() {
611 return batchSize;
615 * @return The end time in milliseconds, or {@code null} if none was provided.
617 public Long getEndTimeMillis() {
618 return endTimeUsec != null ? endTimeUsec / 1000 : null;
622 * @return The end time in microseconds, or {@code null} if none was provided.
624 public Long getEndTimeUsec() {
625 return endTimeUsec;
629 * @return Whether or not application logs should be returned.
631 public Boolean getIncludeAppLogs() {
632 return includeAppLogs;
636 * @return Whether or not incomplete request logs should be returned.
638 public Boolean getIncludeIncomplete() {
639 return includeIncomplete;
643 * @return The minimum log level, or {@code null} if none was provided.
645 public LogLevel getMinLogLevel() {
646 return minLogLevel;
650 * @return The start time in milliseconds, or {@code null} if none was provided.
652 public Long getStartTimeMillis() {
653 return startTimeUsec != null ? startTimeUsec / 1000 : null;
657 * @return The start time in microseconds, or {@code null} if none was provided.
659 public Long getStartTimeUsec() {
660 return startTimeUsec;
664 * @return The list of major app versions that should be queried over, or
665 * an empty list if none were set.
667 public List<String> getMajorVersionIds() {
668 return majorVersionIds;
672 * @return The list possibly empty list of module versions that should be queried over.
674 public List<Version> getVersions() {
675 ImmutableList.Builder<Version> builder = ImmutableList.builder();
676 return builder.addAll(versions).build();
680 * @return The list of request ids that should be queried over, or
681 * {@code null} if none were set.
683 public List<String> getRequestIds() {
684 return requestIds;