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

io.github.dibog.AwsCWEventDump Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2018  Dieter Bogdoll
 *
 * 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.
 */

package io.github.dibog;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggerContextVO;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.spi.ContextAware;
import com.amazonaws.services.logs.AWSLogs;
import com.amazonaws.services.logs.model.*;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.Objects.requireNonNull;

class AwsCWEventDump implements Runnable {
    private final RingBuffer queue = new RingBuffer(10);
    private final LoggingEventToString layout;
    private final AwsConfig awsConfig;
    private final boolean createLogGroup;
    private final String groupName;
    private final String streamName;
    private final DateFormat dateFormat;
    private final ContextAware logContext;
    private final Date dateHolder = new Date();
    private final PutLogEventsRequest logEventReq;

    private volatile boolean done = false;

    private AWSLogs awsLogs;
    private String currentStreamName = null;
    private String nextToken = null;

    public AwsCWEventDump( AwsLogAppender aAppender ) {
        logContext = requireNonNull(aAppender, "appender");
        awsConfig = aAppender.awsConfig==null ? new AwsConfig(): aAppender.awsConfig;
        createLogGroup = aAppender.createLogGroup;
        groupName = requireNonNull(aAppender.groupName, "appender.groupName");
        logEventReq = new PutLogEventsRequest().withLogGroupName(groupName);
        streamName = requireNonNull(aAppender.streamName, "appender.streamName");

        if(aAppender.layout==null) {
            layout = new LoggingEventToStringImpl();
        }
        else {
            final Layout delegate = aAppender.layout;
            layout = new LoggingEventToString() {
                @Override
                public String map(ILoggingEvent event) {
                    return delegate.doLayout(event);
                }
            };
        }

        if(aAppender.dateFormat==null || aAppender.dateFormat.trim().isEmpty()) {
            dateFormat = null;
        }
        else {
            dateFormat = new SimpleDateFormat(aAppender.dateFormat);
        }
    }

    private void closeStream() {
        currentStreamName = null;
    }

    private void openStream(String aNewStreamName) {

        if(awsLogs==null) {
            try {
                awsLogs = awsConfig.createAWSLogs();
            }
            catch(Exception e) {
                logContext.addError("Exception while opening AWSLogs. Shutting down the cloud watch logger.", e);
                shutdown();
            }
        }

        if(createLogGroup) {
            if (findLogGroup(groupName)==null) {
                logContext.addInfo("creating log group '"+groupName+"'");
                try {
                    awsLogs.createLogGroup(new CreateLogGroupRequest(groupName));
                }
                catch(OperationAbortedException e) {
                    logContext.addError("couldn't create log group '"+groupName+"': "+e.getLocalizedMessage());
                }
            }
        }

        LogStream stream = findLogStream(groupName, aNewStreamName);
        if(stream==null) {
            try {
                logContext.addInfo("creating log stream '"+streamName+"'");
                awsLogs.createLogStream(new CreateLogStreamRequest(groupName, aNewStreamName));
            }
            catch(Exception e) {
                logContext.addError("Exception while creating log stream ( "+groupName+" / "+aNewStreamName+" ). Shutting down the cloud watch logger.", e);
                shutdown();
            }
            nextToken = null;
        }
        else {
            nextToken = stream.getUploadSequenceToken();
        }

        logEventReq.withLogStreamName(aNewStreamName);
        currentStreamName = aNewStreamName;

    }

    private LogGroup findLogGroup(String aName) {
        DescribeLogGroupsResult result = awsLogs.describeLogGroups(
                new DescribeLogGroupsRequest()
                        .withLogGroupNamePrefix(groupName)
        );
        for (LogGroup group : result.getLogGroups()) {
            if (group.getLogGroupName().equals(aName)) {
                return group;
            }
        }
        return null;
    }

    private LogStream findLogStream(String aGroupName, String aStreamName) {
        try {
            DescribeLogStreamsResult result = awsLogs.describeLogStreams(
                    new DescribeLogStreamsRequest(groupName)
                            .withLogStreamNamePrefix(aStreamName)
            );
            for (LogStream stream : result.getLogStreams()) {
                if (stream.getLogStreamName().equals(aStreamName)) {
                    return stream;
                }
            }
        }
        catch(Exception e) {
            logContext.addError("Exception while trying to describe log stream ( "+aGroupName+"/"+aStreamName+" ).  Shutting down the cloud watch logger.", e);
            shutdown();
        }

        return null;
    }

    private void log(Collection aEvents) {
        if(dateFormat!=null) {
            dateHolder.setTime(System.currentTimeMillis());
            String newStreamName = streamName + "-" + dateFormat.format(dateHolder);

            if ( !newStreamName.equals(currentStreamName) ) {
                logContext.addInfo("stream name changed from '"+currentStreamName+"' to '"+newStreamName+"'");
                closeStream();
                openStream(newStreamName);
            }
        }
        else if (awsLogs==null) {
            closeStream();
            openStream(streamName);
        }

        Collection events =  new ArrayList<>(aEvents.size());
        for(ILoggingEvent event : aEvents) {
            if(event.getLoggerContextVO()!=null) {
                events.add(new InputLogEvent()
                        .withTimestamp(event.getTimeStamp())
                        .withMessage(layout.map(event)));
            }
        }

        try {
            nextToken = awsLogs.putLogEvents(
                    logEventReq
                            .withSequenceToken(nextToken)
                            .withLogEvents(events)
            ).getNextSequenceToken();
        }
        catch(Exception e) {
            logContext.addError("Exception while adding log events.", e);
        }
    }

    public void shutdown() {
        done = true;
    }

    public void queue(ILoggingEvent event) {
        queue.put(event);
    }

    public void run() {
        List collections = new LinkedList();
        LoggerContextVO context = null;
        while(!done) {

            try {
                int[] nbs = queue.drainTo(collections);
                if(context==null && !collections.isEmpty()) {
                    context = collections.get(0).getLoggerContextVO();
                }

                int msgProcessed = nbs[0];
                int msgSkipped = nbs[1];
                if(context!=null && msgSkipped>0) {
                    collections.add(new SkippedEvent(msgSkipped, context));
                }
                log(collections);
                collections.clear();
            }
            catch(InterruptedException e) {
                // ignoring
            }
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy