io.techcode.logbulk.pipeline.output.SyslogOutput.java Source code

Java tutorial

Introduction

Here is the source code for io.techcode.logbulk.pipeline.output.SyslogOutput.java

Source

/*
 * The MIT License (MIT)
 * <p>
 * Copyright (c) 2017
 * <p>
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * <p>
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * <p>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package io.techcode.logbulk.pipeline.output;

import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import io.netty.buffer.ByteBufOutputStream;
import io.techcode.logbulk.util.SyslogHeader;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.EncodeException;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;

import java.util.Map;

import static com.google.common.base.Preconditions.checkState;

/**
 * Syslog output pipeline component.
 */
public class SyslogOutput extends TcpOutput {

    // Some constants
    private static final String CONF_FRAMING = "framing";
    private static final String CONF_MAPPING = "mapping";
    private static final String CONF_DELIMITER = "delimiter";

    // Settings
    private Map<SyslogHeader, String> mapping;
    private String delimiter;

    @Override
    public void onStart() {
        // Setup mapping
        JsonObject map = config.getJsonObject(CONF_MAPPING, new JsonObject());
        mapping = Maps.newEnumMap(SyslogHeader.class);
        for (String entry : map.fieldNames()) {
            mapping.put(SyslogHeader.byName(entry), map.getString(entry));
        }

        // Setup framing
        String framing = config.getString(CONF_FRAMING);
        if ("delimited".equals(framing)) {
            delimiter = config.getString(CONF_DELIMITER);
        }
    }

    @Override
    public Handler<JsonObject> encoder() {
        return data -> {
            Buffer buf = Buffer.buffer();

            // Add facility
            buf.appendString("<");
            String facility = mapping.get(SyslogHeader.FACILITY);
            String severity = mapping.get(SyslogHeader.SEVERITY);
            if (mapping.containsKey(SyslogHeader.FACILITY) && mapping.containsKey(SyslogHeader.SEVERITY)
                    && data.containsKey(facility) && data.containsKey(severity)) {
                int acc = data.getInteger(facility) * 8 + data.getInteger(severity);
                buf.appendString(String.valueOf(acc));
            }
            buf.appendString(">1 ");

            // Add timestamp
            populate(buf, SyslogHeader.TIMESTAMP, data);

            // Add hostname
            populate(buf, SyslogHeader.HOST, data);

            // Add application
            populate(buf, SyslogHeader.APPLICATION, data);

            // Add processus
            populate(buf, SyslogHeader.PROCESSUS, data);

            // Add msg id
            populate(buf, SyslogHeader.ID, data);

            // Add structured data
            populate(buf, SyslogHeader.DATA, data);

            // Add message
            String message = mapping.get(SyslogHeader.MESSAGE);
            if (mapping.containsKey(SyslogHeader.MESSAGE)) {
                if (data.containsKey(message)) {
                    buf.appendString(String.valueOf(data.getValue(message)));
                } else {
                    try {
                        Json.mapper.writeValue(new ByteBufOutputStream(buf.getByteBuf()), data.getMap());
                    } catch (Exception e) {
                        throw new EncodeException("Failed to encode as JSON: " + e.getMessage());
                    }
                }
            }

            getConnection().write(framing(buf));
        };
    }

    /**
     * Framing based on buffer.
     *
     * @param buf buffer involved.
     * @return framed buffer.
     */
    private Buffer framing(Buffer buf) {
        if (delimiter != null) {
            return buf.appendString(delimiter);
        } else {
            return Buffer.buffer().appendString(String.valueOf(buf.length())).appendString(" ").appendBuffer(buf);
        }
    }

    /**
     * Populate header based on data.
     *
     * @param buf    buffer to write in.
     * @param header header to populate.
     * @param data   data involved.
     */
    private void populate(Buffer buf, SyslogHeader header, JsonObject data) {
        String key = mapping.get(header);
        if (mapping.containsKey(header) && data.containsKey(key)) {
            buf.appendString(String.valueOf(data.getValue(key)));
            buf.appendString(" ");
        } else {
            buf.appendString("- ");
        }
    }

    @Override
    protected void checkConfig(JsonObject config) {
        super.checkConfig(config);
        checkState(validFraming(config.getString(CONF_FRAMING)), "The framing is required");
        if ("delimited".equals(config.getString(CONF_FRAMING))) {
            checkState(!Strings.isNullOrEmpty(config.getString(CONF_DELIMITER)), "The delimiter is required");
        }
    }

    /**
     * Validate framing option.
     *
     * @param framing framing option.
     * @return true if the option is valid, otherwise false.
     */
    private boolean validFraming(String framing) {
        return !Strings.isNullOrEmpty(framing) && ("counted".equals(framing) | "delimited".equals(framing));
    }

}