Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.fabric8.maven.docker.access.log;/*
*
* Copyright 2014 Roland Huss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Charsets;
import com.google.common.io.ByteStreams;
import io.fabric8.maven.docker.access.DockerAccessException;
import io.fabric8.maven.docker.access.UrlBuilder;
import io.fabric8.maven.docker.access.util.RequestUtil;
import io.fabric8.maven.docker.util.Timestamp;
import org.apache.commons.codec.binary.Hex;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
/**
* Extractor for parsing the response of a log request
*
* @author roland
* @since 28/11/14
*/
public class LogRequestor extends Thread implements LogGetHandle {
// Patter for matching log entries
static final Pattern LOG_LINE = Pattern.compile("^\\[?(?[^\\s\\]]*)]? (?.*?)\\s*$", Pattern.DOTALL);
private final CloseableHttpClient client;
private final String containerId;
// callback called for each line extracted
private LogCallback callback;
private DockerAccessException exception;
// Remember for asynchronous handling so that the request can be aborted from the outside
private HttpUriRequest request;
private final UrlBuilder urlBuilder;
/**
* Create a helper object for requesting log entries synchronously ({@link #fetchLogs()}) or asynchronously ({@link #start()}.
*
* @param client HTTP client to use for requesting the docker host
* @param urlBuilder builder that creates docker urls
* @param containerId container for which to fetch the host
* @param callback callback to call for each line received
*/
public LogRequestor(CloseableHttpClient client, UrlBuilder urlBuilder, String containerId, LogCallback callback) {
this.client = client;
this.containerId = containerId;
this.urlBuilder = urlBuilder;
this.callback = callback;
this.exception = null;
}
/**
* Get logs and feed a callback with the content
*/
public void fetchLogs() {
try {
callback.open();
this.request = getLogRequest(false);
final HttpResponse response = client.execute(request);
parseResponse(response);
} catch (LogCallback.DoneException e) {
// Signifies we're finished with the log stream.
} catch (IOException exp) {
callback.error(exp.getMessage());
} finally {
callback.close();
}
}
// Fetch log asynchronously as stream and follow stream
public void run() {
try {
callback.open();
this.request = getLogRequest(true);
final HttpResponse response = client.execute(request);
parseResponse(response);
} catch (LogCallback.DoneException e) {
// Signifies we're finished with the log stream.
} catch (IOException e) {
callback.error("IO Error while requesting logs: " + e + " " + Thread.currentThread().getName());
} finally {
callback.close();
}
}
private static class NoBytesReadException extends IOException {
public NoBytesReadException() {
}
}
/**
* This is a copy of ByteStreams.readFully(), with the slight change that it throws
* NoBytesReadException if zero bytes are read. Otherwise it is identical.
*
* @param in
* @param bytes
* @throws IOException
*/
private void readFully(InputStream in, byte[] bytes) throws IOException {
int read = ByteStreams.read(in, bytes, 0, bytes.length);
if (read == 0) {
throw new NoBytesReadException();
} else if (read != bytes.length) {
throw new EOFException("reached end of stream after reading "
+ read + " bytes; " + bytes.length + " bytes expected");
}
}
private boolean readStreamFrame(InputStream is) throws IOException, LogCallback.DoneException {
// Read the header, which is composed of eight bytes. The first byte is an integer
// indicating the stream type (0 = stdin, 1 = stdout, 2 = stderr), the next three are thrown
// out, and the final four are the size of the remaining stream as an integer.
ByteBuffer headerBuffer = ByteBuffer.allocate(8);
headerBuffer.order(ByteOrder.BIG_ENDIAN);
try {
this.readFully(is, headerBuffer.array());
} catch (NoBytesReadException e) {
// Not bytes read for stream. Return false to stop consuming stream.
return false;
} catch (EOFException e) {
throw new IOException("Failed to read log header. Could not read all 8 bytes. " + e.getMessage(), e);
}
// Grab the stream type (stdout, stderr, stdin) from first byte and throw away other 3 bytes.
int type = headerBuffer.get();
// Skip three bytes, then read size from remaining four bytes.
int size = headerBuffer.getInt(4);
// Ignore empty messages and keep reading.
if (size <= 0) {
return true;
}
// Read the actual message
ByteBuffer payload = ByteBuffer.allocate(size);
try {
ByteStreams.readFully(is, payload.array());
} catch (EOFException e) {
throw new IOException("Failed to read log message. Could not read all " + size + " bytes. " + e.getMessage() +
" [ Header: " + Hex.encodeHexString(headerBuffer.array()) + "]", e);
}
String message = Charsets.UTF_8.newDecoder().decode(payload).toString();
callLogCallback(type, message);
return true;
}
private void parseResponse(HttpResponse response) throws LogCallback.DoneException, IOException {
final StatusLine status = response.getStatusLine();
if (status.getStatusCode() != 200) {
exception = new DockerAccessException("Error while reading logs (" + status + ")");
throw new LogCallback.DoneException();
}
try (InputStream is = response.getEntity().getContent()) {
while (true) {
if (!readStreamFrame(is)) {
return;
}
}
}
}
private void callLogCallback(int type, String txt) throws LogCallback.DoneException {
Matcher matcher = LOG_LINE.matcher(txt);
if (!matcher.matches()) {
callback.error(String.format("Invalid log format for '%s' (expected: \"\") [%04x %04x]",
txt,(int) (txt.toCharArray())[0],(int) (txt.toCharArray())[1]));
throw new LogCallback.DoneException();
}
Timestamp ts = new Timestamp(matcher.group("timestamp"));
String logTxt = matcher.group("entry");
callback.log(type, ts, logTxt);
}
private HttpUriRequest getLogRequest(boolean follow) {
return RequestUtil.newGet(urlBuilder.containerLogs(containerId, follow));
}
@Override
public void finish() {
if (request != null) {
request.abort();
request = null;
}
}
@Override
public boolean isError() {
return exception != null;
}
@Override
public DockerAccessException getException() {
return exception;
}
}