ch.qos.logback.more.appenders.DynamoDBLogbackAppender.java Source code

Java tutorial

Introduction

Here is the source code for ch.qos.logback.more.appenders.DynamoDBLogbackAppender.java

Source

/**
 * Copyright (c) 2012 sndyuk <sanada@sndyuk.com>
 *
 * 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 ch.qos.logback.more.appenders;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;

import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.QueryResult;

public class DynamoDBLogbackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    private static final int MSG_SIZE_LIMIT = 65535;

    private static final class DynamoDBDaemonAppender extends DaemonAppender<ILoggingEvent> {

        private final String tableName;
        private final String instanceName;
        private long id;
        private final AmazonDynamoDBClient dynamoClient;
        private final Layout<ILoggingEvent> layout;

        DynamoDBDaemonAppender(String tableName, String instanceName, long lastId,
                AmazonDynamoDBClient dynamoClient, Layout<ILoggingEvent> layout, int maxQueueSize) {
            super(maxQueueSize);
            this.tableName = tableName;
            this.instanceName = instanceName;
            this.id = lastId;
            this.dynamoClient = dynamoClient;
            this.layout = layout;
        }

        @Override
        protected void append(ILoggingEvent rawData) {
            String msg = null;
            if (layout != null) {
                msg = layout.doLayout(rawData);
            } else {
                msg = rawData.toString();
            }
            if (msg != null && msg.length() > MSG_SIZE_LIMIT) {
                msg = msg.substring(0, MSG_SIZE_LIMIT);
            }

            Map<String, AttributeValue> data = new HashMap<String, AttributeValue>(4);
            data.put("instance", new AttributeValue().withS(instanceName));
            data.put("id", new AttributeValue().withN(String.valueOf(++id)));
            data.put("msg", new AttributeValue().withS(msg));

            PutItemRequest itemRequest = new PutItemRequest().withTableName(tableName).withItem(data);
            dynamoClient.putItem(itemRequest);
        }

        @Override
        protected void close() {
            try {
                super.close();
            } finally {
                dynamoClient.shutdown();
            }
        }
    }

    private DaemonAppender<ILoggingEvent> appender;

    private boolean initializeAppender() {
        try {
            PropertiesCredentials credentials = new PropertiesCredentials(
                    getClass().getClassLoader().getResourceAsStream(dynamodbCredentialFilePath));
            AmazonDynamoDBClient dynamoClient = new AmazonDynamoDBClient(credentials);
            dynamoClient.setEndpoint(dynamodbEndpoint);
            appender = new DynamoDBDaemonAppender(outputTableName, instanceName,
                    getLastId(outputTableName, instanceName, dynamoClient), dynamoClient, layout, maxQueueSize);
            return true;
        } catch (Exception e) {
            System.err.println("Could not initialize " + DynamoDBLogbackAppender.class.getCanonicalName()
                    + " ( will try to initialize again later ): " + e);
            return false;
        }
    }

    private static long getLastId(String tableName, String instanceName, AmazonDynamoDBClient dynamoClient) {
        QueryRequest queryRequest = new QueryRequest().withTableName(tableName)
                .withKeyConditionExpression("instance = :pk")
                .addExpressionAttributeValuesEntry(":pk", new AttributeValue().withS(instanceName))
                .withScanIndexForward(false).withLimit(1);
        QueryResult result = dynamoClient.query(queryRequest);
        List<Map<String, AttributeValue>> items = result.getItems();
        if (items == null || items.size() == 0) {
            return 0L;
        } else {
            return Long.valueOf(items.get(0).get("id").getN());
        }
    }

    @Override
    protected void append(ILoggingEvent eventObject) {
        if (appender == null) {
            synchronized (this) {
                if (!initializeAppender()) {
                    System.err.println(
                            "The log which supposed to be added to DynamoDB was not added because the dynamo db appender could not be initialized. Ignored the message: "
                                    + System.lineSeparator() + eventObject.toString());
                    return;
                }
            }
            this.append(eventObject);
            return;
        }
        eventObject.prepareForDeferredProcessing();
        appender.log(eventObject);
    }

    @Override
    public void stop() {
        try {
            super.stop();
        } finally {
            synchronized (this) {
                if (appender != null) {
                    appender.close();
                }
            }
        }
    }

    private String dynamodbCredentialFilePath;
    private String dynamodbEndpoint;
    private String outputTableName;
    // An quque name for preventing conflict with other instances.
    private String instanceName;
    // Max queue size of logs which is waiting to be sent (When it reach to the max size, the log will be disappeared).
    private int maxQueueSize;
    private Layout<ILoggingEvent> layout;

    public String getDynamodbCredentialFilePath() {
        return dynamodbCredentialFilePath;
    }

    public void setDynamodbCredentialFilePath(String dynamodbCredentialFilePath) {
        this.dynamodbCredentialFilePath = dynamodbCredentialFilePath;
    }

    public String getDynamodbEndpoint() {
        return dynamodbEndpoint;
    }

    public void setDynamodbEndpoint(String dynamodbEndpoint) {
        this.dynamodbEndpoint = dynamodbEndpoint;
    }

    public String getOutputTableName() {
        return outputTableName;
    }

    public void setOutputTableName(String outputTableName) {
        this.outputTableName = outputTableName;
    }

    public String getInstanceName() {
        return instanceName;
    }

    public void setInstanceName(String instanceName) {
        this.instanceName = instanceName;
    }

    public int getMaxQueueSize() {
        return maxQueueSize;
    }

    public void setMaxQueueSize(int maxQueueSize) {
        this.maxQueueSize = maxQueueSize;
    }

    public Layout<ILoggingEvent> getLayout() {
        return layout;
    }

    public void setLayout(Layout<ILoggingEvent> layout) {
        this.layout = layout;
    }
}