001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.mongodb4;
018
019import org.apache.logging.log4j.Logger;
020import org.apache.logging.log4j.core.appender.AppenderLoggingException;
021import org.apache.logging.log4j.core.appender.nosql.AbstractNoSqlConnection;
022import org.apache.logging.log4j.core.appender.nosql.NoSqlConnection;
023import org.apache.logging.log4j.core.appender.nosql.NoSqlObject;
024import org.apache.logging.log4j.status.StatusLogger;
025import org.bson.Document;
026
027import com.mongodb.ConnectionString;
028import com.mongodb.MongoException;
029import com.mongodb.client.MongoClient;
030import com.mongodb.client.MongoCollection;
031import com.mongodb.client.MongoDatabase;
032import com.mongodb.client.model.CreateCollectionOptions;
033import com.mongodb.client.result.InsertOneResult;
034
035/**
036 * The MongoDB implementation of {@link NoSqlConnection}.
037 */
038public final class MongoDb4Connection extends AbstractNoSqlConnection<Document, MongoDb4DocumentObject> {
039
040    private static final Logger LOGGER = StatusLogger.getLogger();
041
042    private static MongoCollection<Document> getOrCreateMongoCollection(final MongoDatabase database,
043            final String collectionName, final boolean isCapped, final Integer sizeInBytes) {
044        try {
045            LOGGER.debug("Gettting collection '{}'...", collectionName);
046            // throws IllegalArgumentException if collectionName is invalid
047            final MongoCollection<Document> found = database.getCollection(collectionName);
048            LOGGER.debug("Got collection {}", found);
049            return found;
050        } catch (final IllegalStateException e) {
051            LOGGER.debug("Collection '{}' does not exist.", collectionName);
052            final CreateCollectionOptions options = new CreateCollectionOptions().capped(isCapped)
053                    .sizeInBytes(sizeInBytes);
054            LOGGER.debug("Creating collection '{}' with options {}...", collectionName, options);
055            database.createCollection(collectionName, options);
056            LOGGER.debug("Created collection.");
057            final MongoCollection<Document> created = database.getCollection(collectionName);
058            LOGGER.debug("Got created collection {}", created);
059            return created;
060        }
061
062    }
063
064    private final ConnectionString connectionString;
065    private final MongoCollection<Document> collection;
066    private final MongoClient mongoClient;
067
068    public MongoDb4Connection(final ConnectionString connectionString, final MongoClient mongoClient,
069            final MongoDatabase mongoDatabase, final boolean isCapped, final Integer sizeInBytes) {
070        this.connectionString = connectionString;
071        this.mongoClient = mongoClient;
072        this.collection = getOrCreateMongoCollection(mongoDatabase, connectionString.getCollection(), isCapped,
073                sizeInBytes);
074    }
075
076    @Override
077    public void closeImpl() {
078        // LOG4J2-1196
079        mongoClient.close();
080    }
081
082    @Override
083    public MongoDb4DocumentObject[] createList(final int length) {
084        return new MongoDb4DocumentObject[length];
085    }
086
087    @Override
088    public MongoDb4DocumentObject createObject() {
089        return new MongoDb4DocumentObject();
090    }
091
092    @Override
093    public void insertObject(final NoSqlObject<Document> object) {
094        try {
095            final Document unwrapped = object.unwrap();
096            LOGGER.debug("Inserting BSON Document {}", unwrapped);
097            InsertOneResult insertOneResult = this.collection.insertOne(unwrapped);
098            LOGGER.debug("Insert MongoDb result {}", insertOneResult);
099        } catch (final MongoException e) {
100            throw new AppenderLoggingException("Failed to write log event to MongoDB due to error: " + e.getMessage(),
101                    e);
102        }
103    }
104
105    @Override
106    public String toString() {
107        return String.format("Mongo4Connection [connectionString=%s, collection=%s, mongoClient=%s]", connectionString,
108                collection, mongoClient);
109    }
110
111}