All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.maven.docker.access.log.LogRequestor Maven / Gradle / Ivy

The newest version!
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.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;

import static java.lang.Math.min;

/**
 * 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
    private static final Pattern LOG_LINE = Pattern.compile("^\\[?([^\\s\\]]*)]?\\s+(.*)\\s*$");
    private final HttpClient 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(HttpClient client, UrlBuilder urlBuilder, String containerId, LogCallback callback) {
        this.client = client;
        this.containerId = containerId;
        
        this.urlBuilder = urlBuilder;

        this.callback = callback;
        this.exception = null;
        this.setDaemon(true);
    }

    /**
     * Get logs and feed a callback with the content
     */
    public void fetchLogs() {
        try {
            HttpResponse resp = client.execute(getLogRequest(false));
            parseResponse(resp);
        } catch (IOException exp) {
            callback.error(exp.getMessage());
        }
    }

    // Fetch log asynchronously as stream and follow stream
    public void run() {
        // Response to extract from

        try {
            request = getLogRequest(true);
            HttpResponse response = client.execute(request);
            parseResponse(response);
        } catch (IOException exp) {
            callback.error("IO Error while requesting logs: " + exp);
        }
    }

    private void parseResponse(HttpResponse response) {
        try (InputStream is = response.getEntity().getContent()) {
            byte[] headBuf = new byte[8];
            while (IOUtils.read(is, headBuf, 0, 8) > 0) {
                int type = headBuf[0];
                int declaredLength = extractLength(headBuf);
                if (declaredLength == 0) {
                    continue;
                }
                byte[] buf = new byte[declaredLength];
                int len = IOUtils.read(is, buf, 0, declaredLength);
                if (len < 1) {
                    callback.error("Invalid log format: Couldn't read " + declaredLength + " bytes from stream");
                    finish();
                    return;
                }
                String txt = new String(buf, 0, len, "UTF-8");

                callLogCallback(type, txt);
            }
            StatusLine status = response.getStatusLine();
            if (status.getStatusCode() != 200) {
                exception = new DockerAccessException("Error while reading logs (" + status + ")");
            }
        } catch (IOException e) {
            callback.error("Cannot process chunk response: " + e);
            finish();
        } catch (LogCallback.DoneException e) {
            // Can be thrown by a log callback which indicates that we are done.
            finish();
        }
    }

    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(1));
        String logTxt = matcher.group(2);
        callback.log(type, ts, logTxt);
    }

    private int extractLength(byte[] b) {
        return b[7] & 0xFF |
               (b[6] & 0xFF) << 8 |
               (b[5] & 0xFF) << 16 |
               (b[4] & 0xFF) << 24;
    }


    private HttpUriRequest getLogRequest(boolean follow) {
        return RequestUtil.newGet(urlBuilder.containerLogs(containerId, follow));
    }

    @Override
    public void finish() {
        if (request != null) {
            request.abort();
        }
    }

    @Override
    public boolean isError() {
        return exception != null;
    }

    @Override
    public DockerAccessException getException() {
        return exception;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy