in api_dev/src/main/java/com/google/appengine/api/log/dev/LocalLogService.java [83:224]
public synchronized LogReadResponse read(Status status, LogReadRequest request) {
LogReadResponse.Builder response = LogReadResponse.newBuilder();
Integer index = 0;
Set<ByteString> requestedIds = null;
if (!request.getRequestIdList().isEmpty()) {
requestedIds = new HashSet<>(request.getRequestIdList());
}
// If the user gave us a request ID to start with, look through our logs
// until we find it. Since it may have been deleted between the time they
// originally were given that value and now, any value with a timestamp
// after this one is acceptable.
if (request.hasOffset()) {
index = null;
BigInteger requestToFind =
new BigInteger(request.getOffset().getRequestId().toStringUtf8(), 16);
for (int i = 0; i < logs.size(); i++) {
BigInteger thisRequestId = new BigInteger(logs.get(i).getRequestId().toStringUtf8(), 16);
if (requestToFind.compareTo(thisRequestId) > 0) {
index = i;
break;
}
}
// There is an unlikely scenario that can occur if the user is promised
// more logs but before they ask for more, they are all deleted. In this
// scenario, return a response to them with no logs and no offset, so
// that they don't ask us for any more logs.
if (index == null) {
return response.build();
}
}
int numResultsFetched = 0;
for (int i = index; i < logs.size(); i++) {
RequestLog thisLog = null;
int j = 0;
for (RequestLog log : logs) {
if (i == j) {
thisLog = log;
break;
}
j++;
}
if (requestedIds != null &&
!requestedIds.contains(thisLog.getRequestId())) {
continue;
}
// We want to get all logs that have started within the bounds the user
// has requested, so check the request's starting time (not its ending
// time) against the provided start/end times.
if (request.hasStartTime()) {
if (request.getStartTime() > thisLog.getEndTime()) {
continue;
}
}
if (request.hasEndTime()) {
if (request.getEndTime() <= thisLog.getEndTime()) {
continue;
}
}
// If the user doesn't want incomplete requests and this request is
// incomplete, don't include it.
if (!request.getIncludeIncomplete() && !thisLog.getFinished()) {
continue;
}
if (!request.getVersionIdList().isEmpty()
&& !request.getVersionIdList().contains(thisLog.getVersionId())
&& thisLog.hasVersionId()) {
continue;
}
if (!request.getModuleVersionList().isEmpty()
&& (thisLog.hasModuleId() || thisLog.hasVersionId())) {
boolean moduleVersionMatch = false;
for (LogModuleVersion moduleVersion : request.getModuleVersionList()) {
if (thisLog.getModuleId().equals(moduleVersion.getModuleId())
&& thisLog.getVersionId().equals(moduleVersion.getVersionId())) {
moduleVersionMatch = true;
}
}
if (!moduleVersionMatch) {
continue;
}
}
if (request.hasMinimumLogLevel()) {
// Find if there are any logs that meet or exceed minimumLogLevel.
// If so (and if the user has specified that they want app logs), add
// all the app logs to the response. If not, don't include this log in
// the response.
boolean logLevelMatched = false;
for (LogLine line : thisLog.getLineList()) {
if (line.getLevel() >= request.getMinimumLogLevel()) {
logLevelMatched = true;
break;
}
}
if (!logLevelMatched) {
continue;
}
}
// At this point, the thisLog proto might only be partial, which is fine in dev mode
// (difference between proto1 and proto2),
// se we are filling mandatory fields with dummy data, so we do not need to change the
// official
// log service implementation.
RequestLog.Builder logCopy = thisLog.toBuilder().clone();
fillRequiredFields(logCopy);
if (!request.getIncludeAppLogs()) {
// If the user doesn't want app logs, make a copy of this log
// that doesn't have that in it and give them that instead.
logCopy.clearLine();
}
response.addLog(logCopy.build());
numResultsFetched++;
if (numResultsFetched >= request.getCount()) {
// If there are more results, set the offset to the next result's
// request id
if (i + 1 < logs.size()) {
ByteString nextOffset = logs.get(i).getRequestId();
LogOffset offset = LogOffset.newBuilder().setRequestId(nextOffset).build();
response.setOffset(offset);
}
break;
}
}
return response.build();
}