|
18 | 18 | import org.apache.commons.collections4.multimap.HashSetValuedHashMap; |
19 | 19 | import org.apache.commons.io.FileUtils; |
20 | 20 | import org.apache.logging.log4j.Logger; |
| 21 | +import org.labkey.api.action.NullSafeBindException; |
21 | 22 | import org.labkey.api.data.ConnectionWrapper; |
| 23 | +import org.labkey.api.data.ContainerManager; |
22 | 24 | import org.labkey.api.data.DbScope; |
| 25 | +import org.labkey.api.data.TSVWriter; |
23 | 26 | import org.labkey.api.data.TransactionFilter; |
| 27 | +import org.labkey.api.data.dialect.BasePostgreSqlDialect; |
24 | 28 | import org.labkey.api.files.FileSystemDirectoryListener; |
25 | 29 | import org.labkey.api.files.FileSystemWatchers; |
26 | 30 | import org.labkey.api.miniprofiler.MiniProfiler; |
27 | 31 | import org.labkey.api.module.ModuleLoader; |
| 32 | +import org.labkey.api.query.QueryForm; |
| 33 | +import org.labkey.api.query.QueryService; |
| 34 | +import org.labkey.api.query.QueryView; |
| 35 | +import org.labkey.api.query.UserSchema; |
| 36 | +import org.labkey.api.security.User; |
28 | 37 | import org.labkey.api.util.logging.LogHelper; |
| 38 | +import org.labkey.api.view.ActionURL; |
| 39 | +import org.labkey.api.view.HttpView; |
| 40 | +import org.labkey.api.view.ViewContext; |
29 | 41 | import org.labkey.api.writer.PrintWriters; |
30 | 42 | import org.labkey.vfs.FileLike; |
31 | 43 |
|
32 | 44 | import java.io.File; |
33 | 45 | import java.io.IOException; |
34 | 46 | import java.io.PrintWriter; |
| 47 | +import java.io.StringWriter; |
35 | 48 | import java.lang.management.ManagementFactory; |
36 | 49 | import java.lang.management.OperatingSystemMXBean; |
37 | 50 | import java.lang.reflect.InvocationTargetException; |
@@ -151,7 +164,7 @@ record ThreadExtraContext(String context, StackTraceElement[] stack, long startT |
151 | 164 | */ |
152 | 165 | public static _PopAutoCloseable pushThreadDumpContext(String context) |
153 | 166 | { |
154 | | - final var arr = _threadDumpExtraContext.computeIfAbsent(Thread.currentThread(), (p1) -> Collections.synchronizedList(new ArrayList<>())); |
| 167 | + final var arr = _threadDumpExtraContext.computeIfAbsent(Thread.currentThread(), (_) -> Collections.synchronizedList(new ArrayList<>())); |
155 | 168 | int size = arr.size(); |
156 | 169 | arr.add(new ThreadExtraContext(context, MiniProfiler.getTroubleshootingStackTrace(), System.currentTimeMillis())); |
157 | 170 | return new _PopAutoCloseable(size); |
@@ -393,6 +406,44 @@ public static synchronized void dumpThreads(LoggerWriter logWriter) |
393 | 406 | logWriter.debug("Completed dump of all open connections"); |
394 | 407 | logWriter.debug("*********************************************"); |
395 | 408 | } |
| 409 | + |
| 410 | + // GitHib Issue 713: Automatically include PG locks and active queries in thread dumps |
| 411 | + UserSchema schema = QueryService.get().getUserSchema(User.getAdminServiceUser(), ContainerManager.getRoot(), BasePostgreSqlDialect.POSTGRES_SCHEMA_NAME); |
| 412 | + // Schema won't exist on SQLServer |
| 413 | + if (schema != null) |
| 414 | + { |
| 415 | + writeTable(logWriter, schema, BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME, "Postgres activity"); |
| 416 | + writeTable(logWriter, schema, BasePostgreSqlDialect.POSTGRES_LOCKS_TABLE_NAME, "Postgres locks"); |
| 417 | + } |
| 418 | + } |
| 419 | + |
| 420 | + private static void writeTable(LoggerWriter logWriter, UserSchema schema, String tableName, String header) |
| 421 | + { |
| 422 | + QueryForm form = new QueryForm(); |
| 423 | + try (var _ = ViewContext.pushMockViewContext(schema.getUser(), schema.getContainer(), new ActionURL())) |
| 424 | + { |
| 425 | + form.setViewContext(HttpView.currentContext()); |
| 426 | + form.setSchemaName(schema.getName()); |
| 427 | + form.setQueryName(tableName); |
| 428 | + QueryView view = QueryView.create(form, new NullSafeBindException(new Object(), "form")); |
| 429 | + logWriter.debug("Starting dump of " + header); |
| 430 | + logWriter.debug("*********************************************"); |
| 431 | + try (TSVWriter writer = view.getTsvWriter()) |
| 432 | + { |
| 433 | + StringWriter stringWriter = new StringWriter(); |
| 434 | + PrintWriter printWriter = new PrintWriter(stringWriter); |
| 435 | + writer.write(printWriter); |
| 436 | + printWriter.flush(); |
| 437 | + logWriter.debug("\n" + stringWriter.toString()); |
| 438 | + } |
| 439 | + catch (IOException e) |
| 440 | + { |
| 441 | + logWriter.error("Failed to write " + header, e); |
| 442 | + } |
| 443 | + logWriter.debug("*********************************************"); |
| 444 | + logWriter.debug("Completed dump of " + header); |
| 445 | + logWriter.debug("*********************************************"); |
| 446 | + } |
396 | 447 | } |
397 | 448 |
|
398 | 449 | static private final Set<String> skipMethods = Set.of("pushThreadDumpContext", "beginTransaction", "ensureTransaction", "execute", "getTroubleshootingStackTrace"); |
|
0 commit comments