public static void registerRoutingAppender(org.apache.hadoop.conf.Configuration conf) {
    if (!HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_SERVER2_LOGGING_OPERATION_ENABLED, false)) {
      // spare some resources, do not register logger if it is not enabled .
      return;
    }
    String loggingLevel = HiveConf.getVar(conf, HiveConf.ConfVars.HIVE_SERVER2_LOGGING_OPERATION_LEVEL);
    OperationLog.LoggingLevel loggingMode = OperationLog.getLoggingLevel(loggingLevel);
    String layout = loggingMode == OperationLog.LoggingLevel.VERBOSE ? verboseLayout : nonVerboseLayout;

    // Create NullAppender
    PluginEntry nullEntry = new PluginEntry();
    nullEntry.setClassName(NullAppender.class.getName());
    nullEntry.setKey("null");
    nullEntry.setName("appender");
    PluginType<NullAppender> nullChildType = new PluginType<NullAppender>(nullEntry, NullAppender.class, "appender");
    Node nullChildNode = new Node(null, "Null", nullChildType);

    // Create default route
    PluginEntry defaultEntry = new PluginEntry();
    defaultEntry.setClassName(Route.class.getName());
    defaultEntry.setKey("route");
    defaultEntry.setName("Route");
    PluginType<Route> defaultType = new PluginType<Route>(defaultEntry, Route.class, "Route");
    Node nullNode = new Node(null, "Route", defaultType);
    nullNode.getChildren().add(nullChildNode);
    Route defaultRoute = Route.createRoute(null, "${ctx:queryId}", nullNode);

    // Create queryId based route
    PluginEntry entry = new PluginEntry();
    entry.setClassName(Route.class.getName());
    entry.setKey("route");
    entry.setName("Route");
    PluginType<Route> type = new PluginType<Route>(entry, Route.class, "Route");
    Node node = new Node(null, "Route", type);

    PluginEntry childEntry = new PluginEntry();
    childEntry.setClassName(HushableRandomAccessFileAppender.class.getName());
    childEntry.setKey("HushableMutableRandomAccess");
    childEntry.setName("appender");
    PluginType<HushableRandomAccessFileAppender> childType = new PluginType<>(childEntry, HushableRandomAccessFileAppender.class, "appender");
    Node childNode = new Node(node, "HushableMutableRandomAccess", childType);
    childNode.getAttributes().put("name", "query-file-appender");
    childNode.getAttributes().put("fileName", "${ctx:operationLogLocation}/${ctx:sessionId}/${ctx:queryId}");
    node.getChildren().add(childNode);

    PluginEntry filterEntry = new PluginEntry();
    filterEntry.setClassName(NameFilter.class.getName());
    filterEntry.setKey("namefilter");
    filterEntry.setName("namefilter");
    PluginType<NameFilter> filterType = new PluginType<>(filterEntry, NameFilter.class, "filter");
    Node filterNode = new Node(childNode, "NameFilter", filterType);
    filterNode.getAttributes().put("loggingLevel", loggingMode.name());
    childNode.getChildren().add(filterNode);

    PluginEntry layoutEntry = new PluginEntry();
    layoutEntry.setClassName(PatternLayout.class.getName());
    layoutEntry.setKey("patternlayout");
    layoutEntry.setName("layout");
    PluginType<PatternLayout> layoutType = new PluginType<>(layoutEntry, PatternLayout.class, "layout");
    Node layoutNode = new Node(childNode, "PatternLayout", layoutType);
    layoutNode.getAttributes().put("pattern", layout);
    childNode.getChildren().add(layoutNode);

    Route mdcRoute = Route.createRoute(null, null, node);
    Routes routes = Routes.createRoutes("${ctx:queryId}", defaultRoute, mdcRoute);

    LoggerContext context = (LoggerContext) LogManager.getContext(false);
    Configuration configuration = context.getConfiguration();

    String timeToLive = String.valueOf(HiveConf
        .getTimeVar(conf, HiveConf.ConfVars.HIVE_SERVER2_OPERATION_LOG_PURGEPOLICY_TIMETOLIVE, TimeUnit.SECONDS));
    PurgePolicy purgePolicy = IdlePurgePolicy.createPurgePolicy(timeToLive, null, "SECONDS", configuration);
    // Hack: due to the (non-standard) way that log4j configuration is extended to introduce the routing appender
    // the life-cycle methods are not called as expected leading to initialization problems (such as the scheduler)
    configuration.getScheduler().incrementScheduledItems();

    RoutingAppender routingAppender = RoutingAppender.createAppender(QUERY_ROUTING_APPENDER,
        "true",
        routes,
        configuration,
        null,
        purgePolicy,
        null);

    LoggerConfig loggerConfig = configuration.getRootLogger();
    loggerConfig.addAppender(routingAppender, null, null);
    context.updateLoggers();
    routingAppender.start();
  }
Programmatically register a routing appender to Log4J configuration, which
automatically writes the log of each query to an individual file.
The equivalent property configuration is as follows:
# queryId based routing file appender
      appender.query-routing.type = Routing
      appender.query-routing.name = query-routing
      appender.query-routing.routes.type = Routes
      appender.query-routing.routes.pattern = $${ctx:queryId}
      # default route
      appender.query-routing.routes.route-default.type = Route
      appender.query-routing.routes.route-default.key = $${ctx:queryId}
      appender.query-routing.routes.route-default.app.type = null
      appender.query-routing.routes.route-default.app.name = Null
      # queryId based route
      appender.query-routing.routes.route-mdc.type = Route
      appender.query-routing.routes.route-mdc.name = IrrelevantName-query-routing
      appender.query-routing.routes.route-mdc.app.type = RandomAccessFile
      appender.query-routing.routes.route-mdc.app.name = query-file-appender
      appender.query-routing.routes.route-mdc.app.fileName = ${sys:hive.log.dir}/${ctx:sessionId}/${ctx:queryId}
      appender.query-routing.routes.route-mdc.app.layout.type = PatternLayout
      appender.query-routing.routes.route-mdc.app.layout.pattern = %d{ISO8601} %5p %c{2}: %m%n
@param conf  the configuration for HiveServer2 instance
ql/src/java/org/apache/hadoop/hive/ql/log/LogDivertAppender.java