class LogFunction extends Scalar<Number, Number> {

    public static final String NAME = "log";

    public static void register(Functions.Builder module) {
        LogBaseFunction.registerLogBaseFunctions(module);
        Log10Function.registerLog10Functions(module);
        LnFunction.registerLnFunctions(module);
    }

    LogFunction(Signature signature, BoundSignature boundSignature) {
        super(signature, boundSignature);
    }

    /**
     * @param result the value to validate
     * @param caller used in the error message for clarification purposes.
     * @return the validated result
     */
    Double validateResult(Double result, String caller) {<FILL_FUNCTION_BODY>}

    static class LogBaseFunction extends LogFunction {

        static void registerLogBaseFunctions(Functions.Builder builder) {
            // log(valueType, baseType) : double
            builder.add(
                scalar(
                    NAME,
                    DataTypes.DOUBLE.getTypeSignature(),
                    DataTypes.DOUBLE.getTypeSignature(),
                    TypeSignature.parse("double precision"))
                    .withFeature(Feature.NULLABLE),
                LogBaseFunction::new
            );
        }

        LogBaseFunction(Signature signature, BoundSignature boundSignature) {
            super(signature, boundSignature);
        }

        @Override
        public Number evaluate(TransactionContext txnCtx, NodeContext nodeCtx, Input<Number>... args) {
            assert args.length == 2 : "number of args must be 2";
            Number value1 = args[0].value();
            Number value2 = args[1].value();

            if (value1 == null || value2 == null) {
                return null;
            }
            double value = value1.doubleValue();
            double base = value2.doubleValue();
            double baseResult = Math.log(base);
            if (baseResult == 0) {
                throw new IllegalArgumentException("log(x, b): given 'base' would result in a division by zero.");
            }
            return validateResult(Math.log(value) / baseResult, "log(x, b)");
        }

    }

    static class Log10Function extends LogFunction {

        static void registerLog10Functions(Functions.Builder builder) {
            // log(double) : double
            builder.add(
                scalar(
                    NAME,
                    DataTypes.DOUBLE.getTypeSignature(),
                    DataTypes.DOUBLE.getTypeSignature())
                    .withFeature(Feature.NULLABLE),
                Log10Function::new
            );
        }

        Log10Function(Signature signature, BoundSignature boundSignature) {
            super(signature, boundSignature);
        }

        @Override
        public Number evaluate(TransactionContext txnCtx, NodeContext nodeCtx, Input<Number>... args) {
            assert args.length == 1 : "number of args must be 1";
            Number value = args[0].value();
            if (value == null) {
                return null;
            }
            return evaluate(value.doubleValue());
        }

        protected Double evaluate(double value) {
            return validateResult(Math.log10(value), "log(x)");
        }

    }

    public static class LnFunction extends Log10Function {

        static void registerLnFunctions(Functions.Builder builder) {
            // ln(double) : double
            builder.add(
                scalar(
                    LnFunction.NAME,
                    DataTypes.DOUBLE.getTypeSignature(),
                    DataTypes.DOUBLE.getTypeSignature())
                    .withFeature(Feature.NULLABLE),
                LnFunction::new
            );
        }

        public static final String NAME = "ln";

        LnFunction(Signature signature, BoundSignature boundSignature) {
            super(signature, boundSignature);
        }

        @Override
        protected Double evaluate(double value) {
            return validateResult(Math.log(value), "ln(x)");
        }
    }
}

        if (result == null) {
            return null;
        }
        if (Double.isNaN(result) || Double.isInfinite(result)) {
            throw new IllegalArgumentException(caller + ": given arguments would result in: '" + result + "'");
        }
        return result;
    
<methods>public BoundSignature boundSignature() ,public Scalar<java.lang.Number,java.lang.Number> compile(List<io.crate.expression.symbol.Symbol>, java.lang.String, io.crate.role.Roles) ,public transient abstract java.lang.Number evaluate(io.crate.metadata.TransactionContext, io.crate.metadata.NodeContext, Input<java.lang.Number>[]) ,public io.crate.expression.symbol.Symbol normalizeSymbol(io.crate.expression.symbol.Function, io.crate.metadata.TransactionContext, io.crate.metadata.NodeContext) ,public io.crate.metadata.functions.Signature signature() <variables>public static final Set<io.crate.metadata.Scalar.Feature> DETERMINISTIC_AND_COMPARISON_REPLACEMENT,public static final Set<io.crate.metadata.Scalar.Feature> DETERMINISTIC_ONLY,public static final Set<io.crate.metadata.Scalar.Feature> NO_FEATURES,protected final non-sealed BoundSignature boundSignature,protected final non-sealed io.crate.metadata.functions.Signature signature