В основном узел в Вашем графике должен не только представить местоположение, но также и самое раннее время, которое можно получить там. Можно думать о нем как об исследовании графика в (место, время) пространство. Кроме того, если Вы имеете (место, t1) и (место, t2) где t1< t2, отбрасывание (место, t2).
Теоретически, это получит самое раннее время поступления для всех возможных мест назначения от Вашего стартового узла. На практике Вам нужна некоторая эвристика для сокращения дорог, которые берут Вас слишком далеко от Вашего места назначения.
Вам также нужна некоторая эвристика для рассмотрения многообещающих маршрутов перед менее многообещающими - если маршрут уводит от места назначения, это менее вероятно (но не полностью вряд ли) быть хорошим.
Альтернативный ответ.
Можно попросить log4j исключить вспомогательный класс с помощью метода
Category.log (String callerFQCN, Priority level, Object message, Throwable t)
и указав вспомогательный класс как 'callerFQCN'.
Например, вот класс, использующий помощник:
public class TheClass {
public static void main(String...strings) {
LoggingHelper.log("Message using full log method in logging helper.");
LoggingHelper.logNotWorking("Message using class info method");
}}
и код помощника:
public class LoggingHelper {
private static Logger LOG = Logger.getLogger(LoggingHelper.class);
public static void log(String message) {
LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null);
}
public static void logNotWorking(String message) {
LOG.info(message);
} }
Первый метод выдаст ожидаемый результат.
Line(TheClass.main(TheClass.java:4)) Message using full log method in logging helper. Line(LoggingHelper.logNotWorking(LoggingHelper.java:12)) Message using class info method
При использовании этого метода Log4j будет работать как обычно, избегая вычисления трассировки стека, если это не требуется.
Добавление деталей в ответ KLE. (извините, пользователь noob, не знаю лучшего способа, чем создать отдельный ответ)
Вместо того, чтобы прикреплять номер строки к сообщению, вы можете поместить его в контекст MDC. См. Org.apache.log4j.MDC
Например:
StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
StackTraceElement stackTraceElement = ...;
int l = stackTraceElement.getLineNumber();
MDC.put("myLineNumber", l);
Это позволяет пользователям использовать mylineNumber в их файле конфигурации log4j
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="Line(%X{myLineNumber})- %m%n"/>
</layout>
Примечание: это позволяет пользователю контролировать, где и как номер строки появляется в сообщении. Однако, поскольку получение трассировки стека очень дорого, вам все равно нужно найти способ отключить эту функцию.
Обратите внимание, что указывать номер строки очень дорого , либо для того, что вы получаете естественным образом от Log4j, либо для следующего. Вы должны принять эту стоимость ...
Вы можете использовать следующие API:
StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
StackTraceElement stackTraceElement = ...;
stackTraceElement.getLineNumber();
Обновлено:
Вам придется рассчитать ее самостоятельно. Итак:
В зависимости от того, как вы предпочитаете ваши регистраторы, ваш вспомогательный метод может:
Это невозможно из коробки. Лучшее, что вы можете сделать в этом случае, - это создать регистратор в вызывающей программе и передать его методу util. Таким образом, вы сможете хотя бы понять, откуда поступил звонок.
Если у вас есть собственные служебные методы ведения журнала, вы можете добавить номер и имя файла в список аргументов ведения журнала и выбрать путь cpp. т.е. предварительно обработайте исходный код для замены тегов, таких как _ LINE _ и _ FILE _, прежде чем выполнять компиляцию. В качестве дополнительного бонуса это не потребует столько ресурсов, сколько вычисление во время выполнения.
Возможно, вы сможете реализовать вспомогательную функцию журнала с помощью элемента трассировки стека, получить номера строк и обойти фреймы с помощью метода с некоторыми конкретными аннотациями, например,
public @interface SkipFrame {}
// helper function
@SkipFrame // not necessary on the concrete log function
void log(String... message) {
// getStackTrace()...
int callerDepth = 2; // a constant number depends on implementation
StackTraceElement callerElement = null;
for (StackTraceElement e: stackTrace) {
String className, methodName = e.getClassName, getMethodName()...
Class callClass = Class.forName(className);
// since there maybe several methods with the same name
// here skip those overloaded methods
Method callMethod = guessWhichMethodWithoutSignature(callClass, methodName);
SkipFrame skipFrame = callMethod.getAnnotation(SkipFrame.class);
if (skipFrame != null)
continue; // skip this stack trace element
if (callerDepth-- == 0) {
callerElement = e;
break;
}
}
assert callerDepth == 0;
assert callerElement != null;
Log4j.info(callerElement.getLineNumber()... + "message... ");
}
@SkipFrame
void logSendMail(Mail mailObject) {
log("Send mail " + mailObject.getSubject());
}
Таким образом, если помощник функция является вложенной, или есть более используемые вспомогательные функции, просто отметьте аннотацию SkipFrame на всех из них, и вы получите правильный номер строки исходного текста, который вам действительно нужен.