Skip to content

Commit a8574e8

Browse files
Merge remote-tracking branch 'origin/develop' into fb_mvtc_empty
2 parents 0383401 + 4005fdf commit a8574e8

8 files changed

Lines changed: 87 additions & 28 deletions

File tree

api/src/org/labkey/api/data/dialect/BasePostgreSqlDialect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ public abstract class BasePostgreSqlDialect extends SqlDialect
7070
// Issue 52190: Expose troubleshooting data that supports postgreSQL-specific analysis
7171
public static final String POSTGRES_SCHEMA_NAME = "postgres";
7272

73+
public static final String POSTGRES_STAT_ACTIVITY_TABLE_NAME = "pg_stat_activity";
74+
public static final String POSTGRES_LOCKS_TABLE_NAME = "pg_locks";
75+
public static final String POSTGRES_TABLE_SIZES_TABLE_NAME = "pg_tablesizes";
76+
7377
private final Map<String, Integer> _domainScaleMap = new CopyOnWriteHashMap<>();
7478

7579
private HtmlString _adminWarning = null;

api/src/org/labkey/api/util/DateUtil.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ private DateUtil()
8787
private static final Locale _localeDefault = Locale.getDefault();
8888
private static final TimeZone _timezoneDefault = TimeZone.getDefault();
8989

90-
private static final String ISO_DATE_FORMAT_STRING = "yyyy-MM-dd";
91-
private static final String ISO_SHORT_TIME_FORMAT_STRING = "HH:mm";
92-
private static final String ISO_DATE_SHORT_TIME_FORMAT_STRING = ISO_DATE_FORMAT_STRING + " " + ISO_SHORT_TIME_FORMAT_STRING;
93-
private static final String ISO_TIME_FORMAT_STRING = "HH:mm:ss";
94-
private static final String ISO_LONG_TIME_FORMAT_STRING = "HH:mm:ss.SSS";
95-
private static final String ISO_DATE_TIME_FORMAT_STRING = ISO_DATE_FORMAT_STRING + " " + ISO_LONG_TIME_FORMAT_STRING;
90+
public static final String ISO_DATE_FORMAT_STRING = "yyyy-MM-dd";
91+
public static final String ISO_SHORT_TIME_FORMAT_STRING = "HH:mm";
92+
public static final String ISO_DATE_SHORT_TIME_FORMAT_STRING = ISO_DATE_FORMAT_STRING + " " + ISO_SHORT_TIME_FORMAT_STRING;
93+
public static final String ISO_TIME_FORMAT_STRING = "HH:mm:ss";
94+
public static final String ISO_LONG_TIME_FORMAT_STRING = "HH:mm:ss.SSS";
95+
public static final String ISO_DATE_TIME_FORMAT_STRING = ISO_DATE_FORMAT_STRING + " " + ISO_LONG_TIME_FORMAT_STRING;
9696

9797
// SimpleDataFormat does not support microseconds, it can only support up to milliseconds
9898
private static final Pattern NON_SIMPLE_PRECISION_TIME_PATTERN = Pattern.compile(".*([0-5][0-9]):([0-5][0-9])\\.(\\d{4,6}).*");

api/src/org/labkey/api/util/DebugInfoDumper.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,33 @@
1818
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
1919
import org.apache.commons.io.FileUtils;
2020
import org.apache.logging.log4j.Logger;
21+
import org.labkey.api.action.NullSafeBindException;
2122
import org.labkey.api.data.ConnectionWrapper;
23+
import org.labkey.api.data.ContainerManager;
2224
import org.labkey.api.data.DbScope;
25+
import org.labkey.api.data.TSVWriter;
2326
import org.labkey.api.data.TransactionFilter;
27+
import org.labkey.api.data.dialect.BasePostgreSqlDialect;
2428
import org.labkey.api.files.FileSystemDirectoryListener;
2529
import org.labkey.api.files.FileSystemWatchers;
2630
import org.labkey.api.miniprofiler.MiniProfiler;
2731
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;
2837
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;
2941
import org.labkey.api.writer.PrintWriters;
3042
import org.labkey.vfs.FileLike;
3143

3244
import java.io.File;
3345
import java.io.IOException;
3446
import java.io.PrintWriter;
47+
import java.io.StringWriter;
3548
import java.lang.management.ManagementFactory;
3649
import java.lang.management.OperatingSystemMXBean;
3750
import java.lang.reflect.InvocationTargetException;
@@ -151,7 +164,7 @@ record ThreadExtraContext(String context, StackTraceElement[] stack, long startT
151164
*/
152165
public static _PopAutoCloseable pushThreadDumpContext(String context)
153166
{
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<>()));
155168
int size = arr.size();
156169
arr.add(new ThreadExtraContext(context, MiniProfiler.getTroubleshootingStackTrace(), System.currentTimeMillis()));
157170
return new _PopAutoCloseable(size);
@@ -393,6 +406,44 @@ public static synchronized void dumpThreads(LoggerWriter logWriter)
393406
logWriter.debug("Completed dump of all open connections");
394407
logWriter.debug("*********************************************");
395408
}
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+
}
396447
}
397448

398449
static private final Set<String> skipMethods = Set.of("pushThreadDumpContext", "beginTransaction", "ensureTransaction", "execute", "getTroubleshootingStackTrace");

core/src/org/labkey/core/admin/AdminController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
import org.labkey.api.data.TableInfo;
134134
import org.labkey.api.data.TransactionFilter;
135135
import org.labkey.api.data.WorkbookContainerType;
136+
import org.labkey.api.data.dialect.BasePostgreSqlDialect;
136137
import org.labkey.api.data.dialect.SqlDialect.ExecutionPlanType;
137138
import org.labkey.api.data.queryprofiler.QueryProfiler;
138139
import org.labkey.api.data.queryprofiler.QueryProfiler.QueryStatTsvWriter;
@@ -2645,7 +2646,7 @@ public class PostgresStatActivityAction extends AbstractPostgresAction
26452646
{
26462647
public PostgresStatActivityAction()
26472648
{
2648-
super(PostgresUserSchema.POSTGRES_STAT_ACTIVITY_TABLE_NAME);
2649+
super(BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME);
26492650
}
26502651
}
26512652

@@ -2654,7 +2655,7 @@ public class PostgresLocksAction extends AbstractPostgresAction
26542655
{
26552656
public PostgresLocksAction()
26562657
{
2657-
super(PostgresUserSchema.POSTGRES_LOCKS_TABLE_NAME);
2658+
super(BasePostgreSqlDialect.POSTGRES_LOCKS_TABLE_NAME);
26582659
}
26592660
}
26602661

@@ -2663,7 +2664,7 @@ public class PostgresTableSizesAction extends AbstractPostgresAction
26632664
{
26642665
public PostgresTableSizesAction()
26652666
{
2666-
super(PostgresUserSchema.POSTGRES_TABLE_SIZES_TABLE_NAME);
2667+
super(BasePostgreSqlDialect.POSTGRES_TABLE_SIZES_TABLE_NAME);
26672668
}
26682669
}
26692670

core/src/org/labkey/core/query/PostgresLocksTable.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
import org.labkey.api.data.BaseColumnInfo;
55
import org.labkey.api.data.JdbcType;
66
import org.labkey.api.data.SQLFragment;
7+
import org.labkey.api.data.dialect.BasePostgreSqlDialect;
78
import org.labkey.api.query.QueryForeignKey;
89

910
/** Backed by pg_locks view */
1011
public class PostgresLocksTable extends AbstractPostgresAdminOnlyTable
1112
{
1213
public PostgresLocksTable(@NotNull PostgresUserSchema userSchema)
1314
{
14-
super(PostgresUserSchema.POSTGRES_LOCKS_TABLE_NAME, userSchema);
15+
super(BasePostgreSqlDialect.POSTGRES_LOCKS_TABLE_NAME, userSchema);
1516

1617
setDescription("Shows info about the currently held Postgres locks");
1718

@@ -28,7 +29,7 @@ public PostgresLocksTable(@NotNull PostgresUserSchema userSchema)
2829
addColumn(new BaseColumnInfo("objsubid", this, JdbcType.INTEGER));
2930
addColumn(new BaseColumnInfo("virtualtransaction", this, JdbcType.VARCHAR));
3031
addColumn(new BaseColumnInfo("pid", this, JdbcType.INTEGER)).
31-
setFk(new QueryForeignKey.Builder(userSchema, null).table(PostgresUserSchema.POSTGRES_STAT_ACTIVITY_TABLE_NAME).raw(true));
32+
setFk(new QueryForeignKey.Builder(userSchema, null).table(BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME).raw(true));
3233
addColumn(new BaseColumnInfo("mode", this, JdbcType.VARCHAR));
3334
addColumn(new BaseColumnInfo("granted", this, JdbcType.BOOLEAN));
3435
addColumn(new BaseColumnInfo("fastpath", this, JdbcType.BOOLEAN));

core/src/org/labkey/core/query/PostgresStatActivityTable.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.labkey.api.data.TableInfo;
1919
import org.labkey.api.data.TableSelector;
2020
import org.labkey.api.data.TransactionFilter;
21+
import org.labkey.api.data.dialect.BasePostgreSqlDialect;
2122
import org.labkey.api.query.AbstractQueryUpdateService;
2223
import org.labkey.api.query.ExprColumn;
2324
import org.labkey.api.query.FieldKey;
@@ -29,6 +30,8 @@
2930
import org.labkey.api.security.permissions.ApplicationAdminPermission;
3031
import org.labkey.api.security.permissions.DeletePermission;
3132
import org.labkey.api.security.permissions.Permission;
33+
import org.labkey.api.util.DateUtil;
34+
import org.labkey.api.util.HtmlString;
3235
import org.labkey.api.util.LinkBuilder;
3336
import org.labkey.api.util.logging.LogHelper;
3437
import org.labkey.api.view.ActionURL;
@@ -47,7 +50,7 @@ public class PostgresStatActivityTable extends AbstractPostgresAdminOnlyTable
4750

4851
public PostgresStatActivityTable(@NotNull PostgresUserSchema userSchema)
4952
{
50-
super(PostgresUserSchema.POSTGRES_STAT_ACTIVITY_TABLE_NAME, userSchema);
53+
super(BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME, userSchema);
5154

5255
setDescription("Shows info about the active Postgres connections and their activity");
5356

@@ -68,8 +71,10 @@ public PostgresStatActivityTable(@NotNull PostgresUserSchema userSchema)
6871
addColumn(new BaseColumnInfo("client_port", this, JdbcType.INTEGER));
6972
addColumn(new BaseColumnInfo("backend_start", this, JdbcType.TIMESTAMP));
7073
addColumn(new BaseColumnInfo("xact_start", this, JdbcType.TIMESTAMP));
71-
addColumn(new BaseColumnInfo("query_start", this, JdbcType.TIMESTAMP));
72-
addColumn(new BaseColumnInfo("state_change", this, JdbcType.TIMESTAMP));
74+
addColumn(new BaseColumnInfo("query_start", this, JdbcType.TIMESTAMP)).
75+
setFormat(DateUtil.ISO_DATE_TIME_FORMAT_STRING);
76+
addColumn(new BaseColumnInfo("state_change", this, JdbcType.TIMESTAMP)).
77+
setFormat(DateUtil.ISO_DATE_TIME_FORMAT_STRING);
7378
addColumn(new BaseColumnInfo("wait_event_type", this, JdbcType.VARCHAR));
7479
addColumn(new BaseColumnInfo("wait_event", this, JdbcType.VARCHAR));
7580
addColumn(new BaseColumnInfo("state", this, JdbcType.VARCHAR));
@@ -231,14 +236,14 @@ public void renderGridCellContents(RenderContext ctx, HtmlWriter out)
231236
}
232237
}
233238
}
234-
String separator = "";
239+
HtmlString separator = HtmlString.EMPTY_STRING;
235240
for (Thread thread : threads)
236241
{
237242
out.write(separator);
238243
ActionURL url = new ActionURL(AdminController.ShowThreadsAction.class, ContainerManager.getRoot());
239244
url.setFragment(thread.getName());
240245
out.write(LinkBuilder.labkeyLink(thread.getName(), url).target("_blank"));
241-
separator = "\n<br/>";
246+
separator = HtmlString.BR;
242247

243248
// Check for HTTP threads and their async counterparts to tie queries to the request that spawned them
244249
var request = TransactionFilter.getRequestSummary(thread);

core/src/org/labkey/core/query/PostgresTableSizesTable.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import org.labkey.api.data.BaseColumnInfo;
55
import org.labkey.api.data.JdbcType;
66
import org.labkey.api.data.SQLFragment;
7+
import org.labkey.api.data.dialect.BasePostgreSqlDialect;
78

89
/** Backed by pg_locks view */
910
public class PostgresTableSizesTable extends AbstractPostgresAdminOnlyTable
1011
{
1112
public PostgresTableSizesTable(@NotNull PostgresUserSchema userSchema)
1213
{
13-
super(PostgresUserSchema.POSTGRES_TABLE_SIZES_TABLE_NAME, userSchema);
14+
super(BasePostgreSqlDialect.POSTGRES_TABLE_SIZES_TABLE_NAME, userSchema);
1415

1516
setDescription("Shows info Postgres table sizes");
1617

core/src/org/labkey/core/query/PostgresUserSchema.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
/** Issue 52190: Expose troubleshooting data that supports postgreSQL-specific analysis */
1616
public class PostgresUserSchema extends UserSchema
1717
{
18-
public static final String POSTGRES_STAT_ACTIVITY_TABLE_NAME = "pg_stat_activity";
19-
public static final String POSTGRES_LOCKS_TABLE_NAME = "pg_locks";
20-
public static final String POSTGRES_TABLE_SIZES_TABLE_NAME = "pg_tablesizes";
21-
2218
public PostgresUserSchema(User user, Container container)
2319
{
2420
super(BasePostgreSqlDialect.POSTGRES_SCHEMA_NAME, "Postgres-specific internal views for database troubleshooting", user, container, CoreSchema.getInstance().getSchema());
@@ -33,11 +29,11 @@ public boolean canReadSchema()
3329
@Override
3430
public @Nullable TableInfo createTable(String name, ContainerFilter cf)
3531
{
36-
if (POSTGRES_STAT_ACTIVITY_TABLE_NAME.equalsIgnoreCase(name))
32+
if (BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME.equalsIgnoreCase(name))
3733
return new PostgresStatActivityTable(this);
38-
if (POSTGRES_LOCKS_TABLE_NAME.equalsIgnoreCase(name))
34+
if (BasePostgreSqlDialect.POSTGRES_LOCKS_TABLE_NAME.equalsIgnoreCase(name))
3935
return new PostgresLocksTable(this);
40-
if (POSTGRES_TABLE_SIZES_TABLE_NAME.equalsIgnoreCase(name))
36+
if (BasePostgreSqlDialect.POSTGRES_TABLE_SIZES_TABLE_NAME.equalsIgnoreCase(name))
4137
return new PostgresTableSizesTable(this);
4238

4339
return null;
@@ -47,8 +43,8 @@ public boolean canReadSchema()
4743
public Set<String> getTableNames()
4844
{
4945
return Set.of(
50-
POSTGRES_LOCKS_TABLE_NAME,
51-
POSTGRES_STAT_ACTIVITY_TABLE_NAME,
52-
POSTGRES_TABLE_SIZES_TABLE_NAME);
46+
BasePostgreSqlDialect.POSTGRES_LOCKS_TABLE_NAME,
47+
BasePostgreSqlDialect.POSTGRES_STAT_ACTIVITY_TABLE_NAME,
48+
BasePostgreSqlDialect.POSTGRES_TABLE_SIZES_TABLE_NAME);
5349
}
5450
}

0 commit comments

Comments
 (0)