1 /*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
139 * <p>
140 * Thus if three processes were all trying to log to fred%u.%g.txt then
141 * they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
142 * the first file in their rotating sequences.
143 * <p>
144 * Note that the use of unique ids to avoid conflicts is only guaranteed
145 * to work reliably when using a local disk file system.
146 *
147 * @since 1.4
148 */
149
150 public class FileHandler extends StreamHandler {
151 private MeteredStream meter;
152 private boolean append;
153 private int limit; // zero => no limit.
154 private int count;
155 private String pattern;
156 private String lockFileName;
157 private FileChannel lockFileChannel;
158 private File files[];
159 private static final int MAX_LOCKS = 100;
160 private static final Set<String> locks = new HashSet<>();
161
162 /**
163 * A metered stream is a subclass of OutputStream that
164 * (a) forwards all its output to a target stream
165 * (b) keeps track of how many bytes have been written
166 */
167 private class MeteredStream extends OutputStream {
168 final OutputStream out;
169 int written;
170
171 MeteredStream(OutputStream out, int written) {
172 this.out = out;
173 this.written = written;
174 }
175
176 @Override
177 public void write(int b) throws IOException {
178 out.write(b);
179 written++;
180 }
181
417 private void openFiles() throws IOException {
418 LogManager manager = LogManager.getLogManager();
419 manager.checkPermission();
420 if (count < 1) {
421 throw new IllegalArgumentException("file count = " + count);
422 }
423 if (limit < 0) {
424 limit = 0;
425 }
426
427 // We register our own ErrorManager during initialization
428 // so we can record exceptions.
429 InitializationErrorManager em = new InitializationErrorManager();
430 setErrorManager(em);
431
432 // Create a lock file. This grants us exclusive access
433 // to our set of output files, as long as we are alive.
434 int unique = -1;
435 for (;;) {
436 unique++;
437 if (unique > MAX_LOCKS) {
438 throw new IOException("Couldn't get lock for " + pattern);
439 }
440 // Generate a lock file name from the "unique" int.
441 lockFileName = generate(pattern, 0, unique).toString() + ".lck";
442 // Now try to lock that filename.
443 // Because some systems (e.g., Solaris) can only do file locks
444 // between processes (and not within a process), we first check
445 // if we ourself already have the file locked.
446 synchronized(locks) {
447 if (locks.contains(lockFileName)) {
448 // We already own this lock, for a different FileHandler
449 // object. Try again.
450 continue;
451 }
452
453 final Path lockFilePath = Paths.get(lockFileName);
454 FileChannel channel = null;
455 int retries = -1;
456 boolean fileCreated = false;
457 while (channel == null && retries++ < 1) {
458 try {
|
1 /*
2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
139 * <p>
140 * Thus if three processes were all trying to log to fred%u.%g.txt then
141 * they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
142 * the first file in their rotating sequences.
143 * <p>
144 * Note that the use of unique ids to avoid conflicts is only guaranteed
145 * to work reliably when using a local disk file system.
146 *
147 * @since 1.4
148 */
149
150 public class FileHandler extends StreamHandler {
151 private MeteredStream meter;
152 private boolean append;
153 private int limit; // zero => no limit.
154 private int count;
155 private String pattern;
156 private String lockFileName;
157 private FileChannel lockFileChannel;
158 private File files[];
159 private static final int DEFAULT_MAX_LOCKS = 100;
160 private static int maxLocks;
161 private static final Set<String> locks = new HashSet<>();
162
163 /*
164 * Initialize maxLocks from the System property if set.
165 * If invalid/no property is provided 100 will be used as a default value.
166 */
167 static {
168 maxLocks = java.security.AccessController.doPrivileged(
169 (PrivilegedAction<Integer>) () ->
170 Integer.getInteger(
171 "jdk.internal.FileHandlerLogging.maxLocks",
172 DEFAULT_MAX_LOCKS)
173 );
174
175 if (maxLocks <= 0) {
176 maxLocks = DEFAULT_MAX_LOCKS;
177 }
178 }
179
180 /**
181 * A metered stream is a subclass of OutputStream that
182 * (a) forwards all its output to a target stream
183 * (b) keeps track of how many bytes have been written
184 */
185 private class MeteredStream extends OutputStream {
186 final OutputStream out;
187 int written;
188
189 MeteredStream(OutputStream out, int written) {
190 this.out = out;
191 this.written = written;
192 }
193
194 @Override
195 public void write(int b) throws IOException {
196 out.write(b);
197 written++;
198 }
199
435 private void openFiles() throws IOException {
436 LogManager manager = LogManager.getLogManager();
437 manager.checkPermission();
438 if (count < 1) {
439 throw new IllegalArgumentException("file count = " + count);
440 }
441 if (limit < 0) {
442 limit = 0;
443 }
444
445 // We register our own ErrorManager during initialization
446 // so we can record exceptions.
447 InitializationErrorManager em = new InitializationErrorManager();
448 setErrorManager(em);
449
450 // Create a lock file. This grants us exclusive access
451 // to our set of output files, as long as we are alive.
452 int unique = -1;
453 for (;;) {
454 unique++;
455 if (unique > maxLocks) {
456 throw new IOException("Couldn't get lock for " + pattern
457 + ", maxLocks: " + maxLocks);
458 }
459 // Generate a lock file name from the "unique" int.
460 lockFileName = generate(pattern, 0, unique).toString() + ".lck";
461 // Now try to lock that filename.
462 // Because some systems (e.g., Solaris) can only do file locks
463 // between processes (and not within a process), we first check
464 // if we ourself already have the file locked.
465 synchronized(locks) {
466 if (locks.contains(lockFileName)) {
467 // We already own this lock, for a different FileHandler
468 // object. Try again.
469 continue;
470 }
471
472 final Path lockFilePath = Paths.get(lockFileName);
473 FileChannel channel = null;
474 int retries = -1;
475 boolean fileCreated = false;
476 while (channel == null && retries++ < 1) {
477 try {
|