Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *    http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  */
0017 package org.apache.spark.sql.execution.datasources.parquet;
0018 
0019 import java.io.Serializable;
0020 import java.util.logging.Handler;
0021 import java.util.logging.Logger;
0022 
0023 import org.apache.parquet.Log;
0024 import org.slf4j.bridge.SLF4JBridgeHandler;
0025 
0026 // Redirects the JUL logging for parquet-mr versions <= 1.8 to SLF4J logging using
0027 // SLF4JBridgeHandler. Parquet-mr versions >= 1.9 use SLF4J directly
0028 final class ParquetLogRedirector implements Serializable {
0029   // Client classes should hold a reference to INSTANCE to ensure redirection occurs. This is
0030   // especially important for Serializable classes where fields are set but constructors are
0031   // ignored
0032   static final ParquetLogRedirector INSTANCE = new ParquetLogRedirector();
0033 
0034   // JUL loggers must be held by a strong reference, otherwise they may get destroyed by GC.
0035   // However, the root JUL logger used by Parquet isn't properly referenced.  Here we keep
0036   // references to loggers in both parquet-mr <= 1.6 and 1.7/1.8
0037   private static final Logger apacheParquetLogger =
0038     Logger.getLogger(Log.class.getPackage().getName());
0039   private static final Logger parquetLogger = Logger.getLogger("parquet");
0040 
0041   static {
0042     // For parquet-mr 1.7 and 1.8, which are under `org.apache.parquet` namespace.
0043     try {
0044       Class.forName(Log.class.getName());
0045       redirect(Logger.getLogger(Log.class.getPackage().getName()));
0046     } catch (ClassNotFoundException ex) {
0047       throw new RuntimeException(ex);
0048     }
0049 
0050     // For parquet-mr 1.6.0 and lower versions bundled with Hive, which are under `parquet`
0051     // namespace.
0052     try {
0053       Class.forName("parquet.Log");
0054       redirect(Logger.getLogger("parquet"));
0055     } catch (Throwable t) {
0056       // SPARK-9974: com.twitter:parquet-hadoop-bundle:1.6.0 is not packaged into the assembly
0057       // when Spark is built with SBT. So `parquet.Log` may not be found.  This try/catch block
0058       // should be removed after this issue is fixed.
0059     }
0060   }
0061 
0062   private ParquetLogRedirector() {
0063   }
0064 
0065   private static void redirect(Logger logger) {
0066     for (Handler handler : logger.getHandlers()) {
0067       logger.removeHandler(handler);
0068     }
0069     logger.setUseParentHandlers(false);
0070     logger.addHandler(new SLF4JBridgeHandler());
0071   }
0072 }