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

codes.vps.logging.fluentd.jdk.FieldExtractorImpl Maven / Gradle / Ivy

package codes.vps.logging.fluentd.jdk;

import codes.vps.logging.fluentd.jdk.util.ForwardString;
import codes.vps.logging.fluentd.jdk.util.StringWinder;
import codes.vps.logging.fluentd.jdk.util.U;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.logging.LogRecord;

public class FieldExtractorImpl implements FieldExtractor {

    private final String fieldName;
    private final Function extract;
    private final static Method getLongThreadID;
    private final static Method getInstant;

    static {

        Method m;
        try {
            m = LogRecord.class.getMethod("getLongThreadID");
        } catch (NoSuchMethodException e) {
            m = null;
        }
        getLongThreadID = m;

        try {
            m = LogRecord.class.getMethod("getInstant");
        } catch (NoSuchMethodException e) {
            m = null;
        }
        getInstant = m;

    }

    @SuppressWarnings("unused")
    public FieldExtractorImpl(String fieldName, Function extract) {
        this.fieldName = fieldName;
        this.extract = extract;
    }

    FieldExtractorImpl(String item) {

        StringWinder sw = new ForwardString(item);

        boolean escape = false;

        StringBuilder sb = new StringBuilder();
        String fieldName = null;
        String format = null;

        int mode = 0;

        while (sw.hasNext()) {

            char c = sw.next();
            if (escape) {
                escape = false;
                sb.append(c);
                continue;
            }

            if (c == '\\') {
                escape = true;
                continue;
            }

            if (mode == 0 && c == '"') {
                mode = 1;
                fieldName = U.sTrim(sb.toString());
                sb = new StringBuilder();
                continue;
            }

            if (mode == 1 && c == '"') {
                mode = 2;
                format = U.sTrim(sb.toString());
                sb = new StringBuilder();
                continue;
            }

            sb.append(c);

        }

        if (escape) {
            throw new IllegalArgumentException("Extractor statement "+item+" ends with an escape character");
        }

        if (mode != 2 || fieldName == null) {
            throw new IllegalArgumentException("No format or fieldName found in "+item);
        }

        String type = U.sTrim(sb.toString());
        if (format == null) { format = ""; }

        this.fieldName = fieldName;

        Function ext = null;

        sw = new ForwardString(format);

        sb = new StringBuilder();

        mode = 0;

        BiFunction, Function, Function> meld = (a, b)->{
            if (b == null) { throw new RuntimeException("That's not supposed to happen"); }
            if (a == null) { return b; }
            return (l)-> String.valueOf(a.apply(l)) + b.apply(l);
        };
        BiFunction, Function, Function> sub = (a,b)->{
            if (b == null || a == null) { throw new RuntimeException("That's not supposed to happen"); }
            return l->a.apply(b.apply(l));
        };

        while (sw.hasNext()) {

            char c = sw.next();

            if (escape) {
                sb.append(c);
                escape = false;
                continue;
            }

            if (c == '\\') {
                escape = true;
                continue;
            }

            if (mode == 0 && c == '$') {
                mode = 1;
                continue;
            }

            if (mode == 1 && c == '[') {
                mode = 3;
                if (sb.length() > 0) {
                    String constant = sb.toString();
                    ext = meld.apply(ext, (l)->constant);
                    sb = new StringBuilder();
                }
                continue;
            }

            if (mode == 3 && c == ']') {
                mode = 0;
                String inlay = sb.toString();
                ext = meld.apply(ext, (l) -> { String v = System.getenv(inlay); if (v == null) { return ""; } return v; });
                sb = new StringBuilder();
                continue;
            }

            if (mode == 1 && c == '{') {
                mode = 2;
                if (sb.length() > 0) {
                    String constant = sb.toString();
                    ext = meld.apply(ext, (l)->constant);
                    sb = new StringBuilder();
                }
                continue;
            }

            if (mode == 2 && c == '}') {
                mode = 0;
                String inlay = sb.toString();
                if ("level".equals(inlay)) {
                    ext = meld.apply(ext, (l)->l.getLevel().getName());
                } else if ("level10n".equals(inlay)) {
                    ext = meld.apply(ext, (l)->l.getLevel().getLocalizedName());
                } else if ("sequence".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getSequenceNumber);
                } else if ("class".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getSourceClassName);
                } else if ("method".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getSourceMethodName);
                } else if ("message".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getMessage);
                } else if ("l10n".equals(inlay)) {
                    ext = meld.apply(ext, U::formatMessage);
                } else if ("params".equals(inlay)) {
                    ext = meld.apply(ext, l->{
                        Object [] ps = l.getParameters();
                        StringBuilder sb2 = new StringBuilder();
                        boolean first = true;
                        if (ps != null) {
                            for (Object p : ps) {
                                if (first) {
                                    first = false;
                                } else {
                                    sb2.append(',');
                                }
                                sb2.append(p);
                            }
                        }
                        return sb2.toString();
                    });
                } else if ("logger".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getLoggerName);
                } else if ("millis".equals(inlay)) {
                    ext = meld.apply(ext, LogRecord::getMillis);
                } else if ("nanos".equals(inlay)) {
                    ext = meld.apply(ext, this::getNanos);
                } else if ("tid".equals(inlay)) {
                    ext = meld.apply(ext, this::getThreadId);
                } else if ("trace".equals(inlay)) {
                    ext = meld.apply(ext, l->U.ifNotNull(l.getThrown(), U::throwableToString, ""));
                } else if (inlay.startsWith("millis,")) {
                    String dtf = inlay.substring(7);
                    SimpleDateFormat sdf;
                    try {
                        sdf = new SimpleDateFormat(dtf);
                    } catch (Exception e) {
                        throw new IllegalArgumentException("Failed to parse date format in "+dtf+" out of "+inlay + " in "+item, e);
                    }
                    ext = meld.apply(ext, (l)->{
                        Date date = new Date(l.getMillis());
                        return sdf.format(date);
                    });
                } else {
                    throw new IllegalArgumentException("Can't resolve "+inlay + " in "+item);
                }
                sb = new StringBuilder();
                continue;
            }

            if (mode == 1) {
                sb.append('$'); // this was a stray '$', without '{'
                mode = 0;
            }

            sb.append(c);

        }

        if (mode == 1) {
            sb.append('$');
        }

        if (mode == 2) {
            throw new IllegalArgumentException("Unterminated } in "+item);
        }

        if (mode == 3) {
            throw new IllegalArgumentException("Unterminated ] in "+item);
        }

        if (sb.length() > 0) {
            String constant = sb.toString();
            ext = meld.apply(ext, (l)->constant);
        }

        if (ext == null) {
            ext = l->"";
        }

        if ("s".equals(type)) {
            ext = sub.apply(String::valueOf, ext);
        } else if ("n".equals(type)) {
            ext = sub.apply(o->new Long(String.valueOf(o)), ext);
        } else if ("b".equals(type)) {
            ext = sub.apply(o-> Boolean.valueOf(String.valueOf(o)), ext);
        } else if (type != null) {
            throw new RuntimeException("Unknown type "+type+" in item");
        }

        extract = ext;

    }

    protected Object getThreadId(LogRecord r) {

        if (getLongThreadID == null) {
            return r.getThreadID();
        } else {
            try {
                return getLongThreadID.invoke(r);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }

    protected Object getNanos(LogRecord r) {

        if (getInstant == null) {
            return BigInteger.valueOf(r.getMillis()).multiply(BigInteger.valueOf(1000000));
        }

        try {
            Instant i = (Instant)getInstant.invoke(r);
            return BigInteger.valueOf(i.getEpochSecond()).multiply(BigInteger.valueOf(1000000000)).add(BigInteger.valueOf(i.getNano()));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    public Object extract(LogRecord l) {
        return extract.apply(l);
    }

    public String getFieldName() {
        return fieldName;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy