@Component(value="blTransactionLifecycleMonitor") public class TransactionLifecycleMonitor extends Object implements BroadleafApplicationListener<TransactionLifecycleEvent>, org.springframework.context.ApplicationContextAware, org.springframework.context.SmartLifecycle, SqlStatementLoggable
LifecycleAwareJpaTransactionManager when a key TransactionLifecycleEvent occurs. Based on this information,
this monitor attempts to detect transaction fault states and report them as part of SUPPORT level logging (SupportLogger).
Currently, the monitor attempts to recognize the following fault states:
loggingReportingLagThreshold. This could indicate the thread has moved on and the transaction was
not correctly finalized.loggingThreshold. This is not necessarily a fault, but may warrant review. Long running or stuck
transactions can account for long resource lock times. Note, this case can later become a stuck thread if the stuckThreshold
has not elapsed.loggingThreshold and no change in thread stack for stuckThreshold. Long running or stuck transactions
can account for long resource lock times.LifecycleAwareJpaTransactionManager via LifecycleAwareJpaTransactionManager.isEnabled().
If no enabled transaction manager is found, the monitor is fully disabled.
The loggingThreshold variable can be controlled via the 'log.transaction.lifecycle.logging.threshold.millis' property.
The default value is 600000.
The stuckThreshold variable can be controlled via the 'log.transaction.lifecycle.stuck.threshold.millis' property.
The default values is 300000.
The loggingPollingResolution variable can be controlled via the 'log.transaction.lifecycle.logging.polling.resolution.millis' property.
The default value is 30000.
The loggingReportingLagThreshold variable can be controlled via the 'log.transaction.lifecycle.reporting.lag.threshold.millis' property.
The default value is 300000.
The countMax variable can be controlled via the 'log.transaction.lifecycle.info.count.max' property. The default value is 5000.
The useCompression variable can be controlled via the 'log.transaction.lifecycle.use.compression' property.
The default value is true.
The abbreviateStatements variable can be controlled via the 'log.transaction.lifecycle.abbreviate.statements' property.
The default value is true.
The abbreviateStatementsLength variable can be controlled via the 'log.transaction.lifecycle.abbreviate.statements.length' property.
The default value is 200.
The decompressStatementForLog variable can be controlled via the 'log.transaction.lifecycle.decompress.statement' property.
The default value is false.
The maxQueryListSize variable can be controlled via the 'log.transaction.lifecycle.query.list.max.size' property.
The default value is 100.
This monitor is intended for temporary usage as part of transaction related debugging efforts. From both a heap utilization
and performance standpoint, this monitor is suitable for production with default settings. Performance impacts should be minor and will generally
be related to creation of the intial call stack, compression of that call stack and subsequent compression of sql statements.
Compression can be turned off via the 'log.transaction.lifecycle.use.compression' for a minor performance benefit at the cost
of additional heap usage. Heap usage can be capped via the 'log.transaction.lifecycle.info.count.max' property, but if the max
happens to be reached, new transactions will not be monitored. This is more a safety net feature than anything and it's not
anticipated that the default max count will be reached during normal usage. Set 'log.transaction.lifecycle.info.count.max' to
-1 to uncap growth.
To avoid overly large disk usage in logs (in case many log statements are emitted with many queries per), the system will truncate
statements to a default length of 200 characters and leave those statements compressed in the logs (if they were configured to be
compressed). See the abbreviateStatements and abbreviateStatementsLength variable to change this behavior.
To view the decompressed version, you'll need to pass the compressed string from the log line to the
decompressLogLine(String) method to see the decompressed version. This can be easily done by writing a simple
main program that instantiates TransactionLifecycleMonitor and calls this method. To emit the uncompressed version of the
queries instead to the logs, change the decompressStatementForLog property value. Finally, by default, the system
will only remember and emit the last 100 queries in the transaction. This value can be tweaked via the maxQueryListSize
variable. Set this value to -1 to uncap the expansion of the query list.| Modifier and Type | Field and Description |
|---|---|
protected boolean |
abbreviateStatements |
protected int |
abbreviateStatementsLength |
protected int |
countMax |
protected boolean |
decompressStatementForLog |
protected boolean |
enabled |
protected Map<Integer,TransactionInfo> |
infos |
protected boolean |
isStarted |
protected long |
loggingPollingResolution |
protected long |
loggingReportingLagThreshold |
protected long |
loggingThreshold |
protected int |
maxQueryListSize |
protected List<TransactionInfoCustomModifier> |
modifiers |
protected long |
stuckThreshold |
protected Timer |
timer |
protected List<LifecycleAwareJpaTransactionManager> |
transactionManagers |
protected boolean |
useCompression |
| Constructor and Description |
|---|
TransactionLifecycleMonitor() |
| Modifier and Type | Method and Description |
|---|---|
protected StackTraceElement[] |
compileThreadInformation(long currentTime,
TransactionInfo info,
Thread thread) |
String |
decompressLogLine(String compressedFromLog) |
protected boolean |
detectExpiry(List<Integer> infosToRemove,
Integer key,
long currentTime,
TransactionInfo info,
StackTraceElement[] elements) |
protected boolean |
detectLeakage(List<Integer> infosToRemove,
Integer key,
long currentTime,
TransactionInfo info) |
protected void |
finalizeTransaction(TransactionLifecycleEvent event) |
int |
getCountMax() |
protected TransactionInfo |
getCurrentTransactionInfo() |
protected javax.persistence.EntityManager |
getEntityManagerFromTransactionObject(Object transactionObject) |
static TransactionLifecycleMonitor |
getInstance() |
long |
getLoggingPollingResolution() |
long |
getLoggingReportingLagThreshold() |
long |
getLoggingThreshold() |
int |
getPhase() |
long |
getStuckThreshold() |
protected void |
groomInProgressTransactionInfos() |
void |
init() |
boolean |
isAsynchronous()
Indicates if this application listener should be run in a background thread if a TaskExecutor is configured.
|
protected boolean |
isAtLeastOneTransactionManagerEnabled() |
boolean |
isAutoStartup() |
boolean |
isRunning() |
boolean |
isUseCompression() |
void |
log(String statement) |
void |
onApplicationEvent(TransactionLifecycleEvent event) |
void |
setApplicationContext(org.springframework.context.ApplicationContext applicationContext) |
void |
setCountMax(int countMax) |
void |
setLoggingPollingResolution(long loggingPollingResolution) |
void |
setLoggingReportingLagThreshold(long loggingReportingLagThreshold) |
void |
setLoggingThreshold(long loggingThreshold) |
void |
setStuckThreshold(long stuckThreshold) |
void |
setUseCompression(boolean useCompression) |
void |
start() |
void |
stop() |
void |
stop(Runnable callback) |
@Autowired(required=false) protected List<LifecycleAwareJpaTransactionManager> transactionManagers
@Autowired(required=false) protected List<TransactionInfoCustomModifier> modifiers
@Value(value="${log.transaction.lifecycle.logging.threshold.millis:600000}")
protected long loggingThreshold
@Value(value="${log.transaction.lifecycle.stuck.threshold.millis:300000}")
protected long stuckThreshold
@Value(value="${log.transaction.lifecycle.logging.polling.resolution.millis:30000}")
protected long loggingPollingResolution
@Value(value="${log.transaction.lifecycle.reporting.lag.threshold.millis:300000}")
protected long loggingReportingLagThreshold
@Value(value="${log.transaction.lifecycle.info.count.max:5000}")
protected int countMax
@Value(value="${log.transaction.lifecycle.use.compression:true}")
protected boolean useCompression
@Value(value="${log.transaction.lifecycle.abbreviate.statements:true}")
protected boolean abbreviateStatements
@Value(value="${log.transaction.lifecycle.abbreviate.statements.length:200}")
protected int abbreviateStatementsLength
@Value(value="${log.transaction.lifecycle.decompress.statement:false}")
protected boolean decompressStatementForLog
@Value(value="${log.transaction.lifecycle.query.list.max.size:100}")
protected int maxQueryListSize
protected Map<Integer,TransactionInfo> infos
protected boolean isStarted
protected boolean enabled
protected Timer timer
public static TransactionLifecycleMonitor getInstance()
@PostConstruct public void init()
public void setApplicationContext(org.springframework.context.ApplicationContext applicationContext)
throws org.springframework.beans.BeansException
setApplicationContext in interface org.springframework.context.ApplicationContextAwareorg.springframework.beans.BeansExceptionpublic boolean isAutoStartup()
isAutoStartup in interface org.springframework.context.SmartLifecyclepublic void stop(Runnable callback)
stop in interface org.springframework.context.SmartLifecyclepublic void start()
start in interface org.springframework.context.Lifecyclepublic void stop()
stop in interface org.springframework.context.Lifecyclepublic boolean isRunning()
isRunning in interface org.springframework.context.Lifecyclepublic int getPhase()
getPhase in interface org.springframework.context.PhasedgetPhase in interface org.springframework.context.SmartLifecyclepublic boolean isAsynchronous()
BroadleafApplicationListenerisAsynchronous in interface BroadleafApplicationListener<TransactionLifecycleEvent>BroadleafApplicationEventMulticasterpublic void onApplicationEvent(TransactionLifecycleEvent event)
onApplicationEvent in interface org.springframework.context.ApplicationListener<TransactionLifecycleEvent>public void log(String statement)
log in interface SqlStatementLoggablepublic String decompressLogLine(String compressedFromLog) throws IOException
decompressLogLine in interface SqlStatementLoggableIOExceptionpublic long getLoggingThreshold()
public void setLoggingThreshold(long loggingThreshold)
public long getStuckThreshold()
public void setStuckThreshold(long stuckThreshold)
public long getLoggingPollingResolution()
public void setLoggingPollingResolution(long loggingPollingResolution)
public long getLoggingReportingLagThreshold()
public void setLoggingReportingLagThreshold(long loggingReportingLagThreshold)
public int getCountMax()
public void setCountMax(int countMax)
public boolean isUseCompression()
public void setUseCompression(boolean useCompression)
protected void groomInProgressTransactionInfos()
protected boolean detectLeakage(List<Integer> infosToRemove, Integer key, long currentTime, TransactionInfo info)
protected boolean detectExpiry(List<Integer> infosToRemove, Integer key, long currentTime, TransactionInfo info, StackTraceElement[] elements)
protected StackTraceElement[] compileThreadInformation(long currentTime, TransactionInfo info, Thread thread)
protected void finalizeTransaction(TransactionLifecycleEvent event)
protected javax.persistence.EntityManager getEntityManagerFromTransactionObject(Object transactionObject)
protected TransactionInfo getCurrentTransactionInfo()
protected boolean isAtLeastOneTransactionManagerEnabled()
Copyright © 2022. All rights reserved.