1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
16 */
17 package org.apache.logging.log4j.util;
18
19 import java.util.NoSuchElementException;
20 import java.util.Stack;
21 import java.util.function.Predicate;
22
23 import org.apache.logging.log4j.status.StatusLogger;
24
25 /**
26 * <em>Consider this class private.</em> Provides various methods to determine the caller class. <h3>Background</h3>
27 */
28 public final class StackLocatorUtil {
29 private static StackLocator stackLocator = null;
30 private static volatile boolean errorLogged;
31
32 static {
33 stackLocator = StackLocator.getInstance();
34 }
35
36 private StackLocatorUtil() {
37 }
38
39 // TODO: return Object.class instead of null (though it will have a null ClassLoader)
40 // (MS) I believe this would work without any modifications elsewhere, but I could be wrong
41
42 // migrated from ReflectiveCallerClassUtility
43 @PerformanceSensitive
44 public static Class<?> getCallerClass(final int depth) {
45 return stackLocator.getCallerClass(depth + 1);
46 }
47
48 public static StackTraceElement getStackTraceElement(final int depth) {
49 return stackLocator.getStackTraceElement(depth + 1);
50 }
51
52 /**
53 * Equivalent to {@link #getCallerClass(String, String)} with an empty {@code pkg}.
54 */
55 // migrated from ClassLoaderContextSelector
56 @PerformanceSensitive
57 public static Class<?> getCallerClass(final String fqcn) {
58 return getCallerClass(fqcn, Strings.EMPTY);
59 }
60
61 /**
62 * Search for a calling class.
63 *
64 * @param fqcn Root class name whose caller to search for.
65 * @param pkg Package name prefix that must be matched after the {@code fqcn} has been found.
66 * @return The caller class that was matched, or null if one could not be located.
67 */
68 @PerformanceSensitive
69 public static Class<?> getCallerClass(final String fqcn, final String pkg) {
70 return stackLocator.getCallerClass(fqcn, pkg);
71 }
72
73 /**
74 * Search for a calling class.
75 *
76 * @param sentinelClass Sentinel class at which to begin searching
77 * @param callerPredicate Predicate checked after the sentinelClass is found
78 * @return the first matching class after <code>sentinelClass</code> is found.
79 */
80 @PerformanceSensitive
81 public static Class<?> getCallerClass(final Class<?> sentinelClass, final Predicate<Class<?>> callerPredicate) {
82 return stackLocator.getCallerClass(sentinelClass, callerPredicate);
83 }
84
85 // added for use in LoggerAdapter implementations mainly
86 @PerformanceSensitive
87 public static Class<?> getCallerClass(final Class<?> anchor) {
88 return stackLocator.getCallerClass(anchor);
89 }
90
91 // migrated from ThrowableProxy
92 @PerformanceSensitive
93 public static Stack<Class<?>> getCurrentStackTrace() {
94 return stackLocator.getCurrentStackTrace();
95 }
96
97 public static StackTraceElement calcLocation(final String fqcnOfLogger) {
98 try {
99 return stackLocator.calcLocation(fqcnOfLogger);
100 } catch (NoSuchElementException ex) {
101 if (!errorLogged) {
102 errorLogged = true;
103 StatusLogger.getLogger().warn("Unable to locate stack trace element for {}", fqcnOfLogger, ex);
104 }
105 return null;
106 }
107 }
108 }