Here is what Log4j does: If the property is specified first see if it contains any commas, if so then there will be multiple configuration files, which essentially does what follows for each file. If not then try to convert it to a URI using the following code:
public static URI toURI(final String path) { try { // Resolves absolute URI return new URI(path); } catch (final URISyntaxException e) { // A file path or a Apache Commons VFS URL might contain blanks. // A file path may start with a driver letter try { final URL url = new URL(path); return new URI(url.getProtocol(), url.getHost(), url.getPath(), null); } catch (MalformedURLException | URISyntaxException nestedEx) { return new File(path).toURI(); } } } The URI is then converted to a ConfigurationSource using: public static ConfigurationSource fromUri(final URI configLocation) { final File configFile = FileUtils.fileFromUri(configLocation); if (configFile != null && configFile.exists() && configFile.canRead()) { try { return new ConfigurationSource(new FileInputStream(configFile), configFile); } catch (final FileNotFoundException ex) { ConfigurationFactory.LOGGER.error("Cannot locate file {}", configLocation.getPath(), ex); } } if (ConfigurationFactory.isClassLoaderUri(configLocation)) { final ClassLoader loader = LoaderUtil.getThreadContextClassLoader(); final String path = ConfigurationFactory.extractClassLoaderUriPath(configLocation); final ConfigurationSource source = fromResource(path, loader); if (source != null) { return source; } } if (!configLocation.isAbsolute()) { // LOG4J2-704 avoid confusing error message thrown by uri.toURL() ConfigurationFactory.LOGGER.error("File not found in file system or classpath: {}", configLocation.toString()); return null; } try { return new ConfigurationSource(configLocation.toURL().openStream(), configLocation.toURL()); } catch (final MalformedURLException ex) { ConfigurationFactory.LOGGER.error("Invalid URL {}", configLocation.toString(), ex); } catch (final Exception ex) { ConfigurationFactory.LOGGER.error("Unable to access {}", configLocation.toString(), ex); } return null; } I should point out that the stack trace log you are seeing is from the above code failing. If any of the above doesn’t work we then try to create a ConfigurationSource using the following code where config is the value of the property and loader is the ThreadContextClassLoader. So even with the error that is shown it is still possible that the file might be found. protected ConfigurationSource getInputFromString(final String config, final ClassLoader loader) { try { final URL url = new URL(config); return new ConfigurationSource(url.openStream(), FileUtils.fileFromUri(url.toURI())); } catch (final Exception ex) { final ConfigurationSource source = ConfigurationSource.fromResource(config, loader); if (source == null) { try { final File file = new File(config); return new ConfigurationSource(new FileInputStream(file), file); } catch (final FileNotFoundException fnfe) { // Ignore the exception LOGGER.catching(Level.DEBUG, fnfe); } } return source; } } ConfigurationSource.fromResource() tries to locate the resource using ClassLoader.getResource() and then constructs a ConfgurationSource if it can find it. And if all else fails we just pass the string to the File constructor and hope for the best. As you can see we aren’t really manipulating the input string that was provided to us, but we are trying any way we can to convert it into some sort of file we can access. If you see something missing in this logic please let us know. Ralph > On Jul 5, 2018, at 1:59 PM, Shawn Heisey <apa...@elyograg.org> wrote: > > On 7/5/2018 11:38 AM, Ralph Goers wrote: >> I have updated the issue you referenced. From what I can tell this is not an >> issue in Log4j. It is an issue with the way file urls work. > > Thanks for your attention. > > The startup script included with Solr versions before 7.4 (using log4j > 1.2.x) also did not have // in the file: URI for the log4j.properties > file, and it works on both Linux and Windows. > > Something else I found in the RFC you linked: > > The syntax given in Section 2 makes the entire authority component, > including the double slashes "//", optional. > > Reading section 2, I didn't actually see that stated. Maybe it's > something clarified by one of the other referenced RFCs. But if we take > that statement at face value, it seems to be saying that a URI without > // should work. It *does* work on Linux. On Windows, this: > > file:C:\path\to\stuff\log4j2.xml > > gets translated into this: > > file:/$CWD/file:C:/path/to/stuff/log4j2.xml > > Where $CWD is the current working directory. Even the "extra" URI added > as a prefix doesn't have the // in it. If instead we use the following, > it works as expected: > > file://C:\path\to\stuff\log4j2.xml > > If you're sure that there's nothing in log4j code that would result in > the strange location, I'd be willing to accept that this problem is > caused by Java or the OS and not log4j. The fact that this doesn't > happen on Linux is even more reason to believe that. I don't know how > likely it is that log4j contains code that behaves differently based on > detected OS ... but I strongly believe that you'd want to avoid that if > possible. > > I believe that we can safely add // to Solr's command script to solve > this issue for our users, because the value should always be a full > absolute path. > > But I would like to pursue the remaining question: When the RFC is > fully and correctly evaluated, is a "file:" URI without "//" considered > valid? If not, then that ends the discussion. If it is considered > valid, then there's another question: Is it Java, log4j, or Windows that > is causing the problem we've seen? > > Another question: What is the stance of the project on whether non-URI > syntax for the log4j.configurationFile system property will be supported > long-term? I can remember running into a problem with logging > configuration in the past (I *think* it was log4j 1.x, but it MIGHT have > been java.util.logging) where the configuration wasn't found until I > added "file:" to turn it into a URI. I did not use // in the URI. This > is a line from the init script I wrote for Solr 4.x versions (when Solr > did not include a startup script): > > LOG_OPTS="-Dlog4j.configuration=file:etc/log4j.properties" > > Thanks, > Shawn > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org > For additional commands, e-mail: log4j-user-h...@logging.apache.org > >