Merge changes Ic0a8ef98,I53f5807e,I14ed5ee8,Id215447c,Ic6c51d2f, ...
* changes:
ReceiveCommits: do not set account name from within processing
CommitValidatorCache: rename to BranchCommitValidator
ReceiveCommits: remove unused ReceiveError enum
ReceiveCommits: document why this class can't be split up further
ReceiveCommits: split off configuration validation in separate function
ReceiveCommits: drop superfluous check
ReceiveCommits: reduce scope of try block
ReceiveCommits: move commit validation into a separate class
ReceiveCommits: use the rejectCommits instance variable always
diff --git a/Documentation/rest-api.txt b/Documentation/rest-api.txt
index 97cca38..8f6a47b 100644
--- a/Documentation/rest-api.txt
+++ b/Documentation/rest-api.txt
@@ -210,6 +210,15 @@
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/suggest_reviewers?trace&q=J
----
+Alternatively request tracing can also be enabled by setting the
+`X-Gerrit-Trace` header:
+
+.Example Request
+----
+ GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/suggest_reviewers?q=J
+ X-Gerrit-Trace: issue/123
+----
+
Enabling tracing results in additional logs with debug information that
are written to the `error_log`. All logs that correspond to the traced
request are associated with the trace ID. The trace ID is returned with
diff --git a/Documentation/user-request-tracing.txt b/Documentation/user-request-tracing.txt
index ac09d3c..8430e97 100644
--- a/Documentation/user-request-tracing.txt
+++ b/Documentation/user-request-tracing.txt
@@ -11,10 +11,10 @@
request type:
* REST API: For REST calls tracing can be enabled by setting the
- `trace` request parameter, the trace ID is returned as
- `X-Gerrit-Trace` header. More information about this can be found in
- the link:rest-api.html#tracing[Request Tracing] section of the
- link:rest-api.html[REST API documentation].
+ `trace` request parameter or the `X-Gerrit-Trace` header, the trace
+ ID is returned as `X-Gerrit-Trace` header. More information about
+ this can be found in the link:rest-api.html#tracing[Request Tracing]
+ section of the link:rest-api.html[REST API documentation].
* SSH API: For SSH calls tracing can be enabled by setting the
`--trace` option. More information about this can be found in
the link:cmd-index.html#trace[Trace] section of the
diff --git a/java/com/google/gerrit/acceptance/HttpResponse.java b/java/com/google/gerrit/acceptance/HttpResponse.java
index 6c03793..3e98d71 100644
--- a/java/com/google/gerrit/acceptance/HttpResponse.java
+++ b/java/com/google/gerrit/acceptance/HttpResponse.java
@@ -14,13 +14,16 @@
package com.google.gerrit.acceptance;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import org.apache.http.Header;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
@@ -61,6 +64,13 @@
return hdr != null ? hdr.getValue() : null;
}
+ public ImmutableList<String> getHeaders(String name) {
+ return Arrays.asList(response.getHeaders(name))
+ .stream()
+ .map(Header::getValue)
+ .collect(toImmutableList());
+ }
+
public boolean hasContent() {
Preconditions.checkNotNull(response, "Response is not initialized.");
return response.getEntity() != null;
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 38fe0e2..10f2638 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -110,6 +110,7 @@
import com.google.gerrit.server.cache.PerThreadCache;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.LockFailureException;
+import com.google.gerrit.server.logging.RequestId;
import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -1322,11 +1323,42 @@
}
private TraceContext enableTracing(HttpServletRequest req, HttpServletResponse res) {
- String traceValue = req.getParameter(ParameterParser.TRACE_PARAMETER);
- return TraceContext.newTrace(
- traceValue != null,
- traceValue,
- (tagName, traceId) -> res.setHeader(X_GERRIT_TRACE, traceId.toString()));
+ // There are 2 ways to enable tracing for REST calls:
+ // 1. by using the 'trace' or 'trace=<trace-id>' request parameter
+ // 2. by setting the 'X-Gerrit-Trace:' or 'X-Gerrit-Trace:<trace-id>' header
+ String traceValueFromHeader = req.getHeader(X_GERRIT_TRACE);
+ String traceValueFromRequestParam = req.getParameter(ParameterParser.TRACE_PARAMETER);
+ boolean doTrace = traceValueFromHeader != null || traceValueFromRequestParam != null;
+
+ // Check whether no trace ID, one trace ID or 2 different trace IDs have been specified.
+ String traceId1;
+ String traceId2;
+ if (!Strings.isNullOrEmpty(traceValueFromHeader)) {
+ traceId1 = traceValueFromHeader;
+ if (!Strings.isNullOrEmpty(traceValueFromRequestParam)
+ && !traceValueFromHeader.equals(traceValueFromRequestParam)) {
+ traceId2 = traceValueFromRequestParam;
+ } else {
+ traceId2 = null;
+ }
+ } else {
+ traceId1 = Strings.emptyToNull(traceValueFromRequestParam);
+ traceId2 = null;
+ }
+
+ // Use the first trace ID to start tracing. If this trace ID is null, a trace ID will be
+ // generated.
+ TraceContext traceContext =
+ TraceContext.newTrace(
+ doTrace,
+ traceId1,
+ (tagName, traceId) -> res.setHeader(X_GERRIT_TRACE, traceId.toString()));
+ // If a second trace ID was specified, add a tag for it as well.
+ if (traceId2 != null) {
+ traceContext.addTag(RequestId.Type.TRACE_ID, traceId2);
+ res.addHeader(X_GERRIT_TRACE, traceId2);
+ }
+ return traceContext;
}
private boolean isDelete(HttpServletRequest req) {
diff --git a/java/com/google/gerrit/lucene/AbstractLuceneIndex.java b/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
index 12f88d5..dc293cd 100644
--- a/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
+++ b/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
@@ -39,7 +39,8 @@
import com.google.gerrit.index.query.FieldBundle;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.IndexUtils;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
+import com.google.gerrit.server.logging.LoggingContextAwareScheduledExecutorService;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import java.io.IOException;
@@ -55,6 +56,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -100,7 +102,7 @@
private final ReferenceManager<IndexSearcher> searcherManager;
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
private final Set<NrtFuture> notDoneNrtFutures;
- private ScheduledThreadPoolExecutor autoCommitExecutor;
+ private ScheduledExecutorService autoCommitExecutor;
AbstractLuceneIndex(
Schema<V> schema,
@@ -129,13 +131,13 @@
delegateWriter = autoCommitWriter;
autoCommitExecutor =
- new ScheduledThreadPoolExecutor(
- 1,
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat(index + " Commit-%d")
- .setDaemon(true)
- .build());
+ new LoggingContextAwareScheduledExecutorService(
+ new ScheduledThreadPoolExecutor(
+ 1,
+ new ThreadFactoryBuilder()
+ .setNameFormat(index + " Commit-%d")
+ .setDaemon(true)
+ .build()));
@SuppressWarnings("unused") // Error handling within Runnable.
Future<?> possiblyIgnoredError =
autoCommitExecutor.scheduleAtFixedRate(
@@ -170,13 +172,13 @@
writerThread =
MoreExecutors.listeningDecorator(
- Executors.newFixedThreadPool(
- 1,
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat(index + " Write-%d")
- .setDaemon(true)
- .build()));
+ new LoggingContextAwareExecutorService(
+ Executors.newFixedThreadPool(
+ 1,
+ new ThreadFactoryBuilder()
+ .setNameFormat(index + " Write-%d")
+ .setDaemon(true)
+ .build())));
reopenThread =
new ControlledRealTimeReopenThread<>(
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index a7824ea..af1228d 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -28,7 +28,8 @@
import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
+import com.google.gerrit.server.logging.LoggingContextAwareScheduledExecutorService;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -75,20 +76,17 @@
if (cacheDir != null) {
executor =
- Executors.newFixedThreadPool(
- 1,
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("DiskCache-Store-%d")
- .build());
+ new LoggingContextAwareExecutorService(
+ Executors.newFixedThreadPool(
+ 1, new ThreadFactoryBuilder().setNameFormat("DiskCache-Store-%d").build()));
cleanup =
- Executors.newScheduledThreadPool(
- 1,
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("DiskCache-Prune-%d")
- .setDaemon(true)
- .build());
+ new LoggingContextAwareScheduledExecutorService(
+ Executors.newScheduledThreadPool(
+ 1,
+ new ThreadFactoryBuilder()
+ .setNameFormat("DiskCache-Prune-%d")
+ .setDaemon(true)
+ .build()));
} else {
executor = null;
cleanup = null;
diff --git a/java/com/google/gerrit/server/config/SysExecutorModule.java b/java/com/google/gerrit/server/config/SysExecutorModule.java
index 2e97a58..f552434 100644
--- a/java/com/google/gerrit/server/config/SysExecutorModule.java
+++ b/java/com/google/gerrit/server/config/SysExecutorModule.java
@@ -19,7 +19,7 @@
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gerrit.server.FanOutExecutor;
import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
@@ -83,18 +83,18 @@
return MoreExecutors.newDirectExecutorService();
}
return MoreExecutors.listeningDecorator(
- MoreExecutors.getExitingExecutorService(
- new ThreadPoolExecutor(
- 1,
- poolSize,
- 10,
- TimeUnit.MINUTES,
- new ArrayBlockingQueue<Runnable>(poolSize),
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("ChangeUpdate-%d")
- .setDaemon(true)
- .build(),
- new ThreadPoolExecutor.CallerRunsPolicy())));
+ new LoggingContextAwareExecutorService(
+ MoreExecutors.getExitingExecutorService(
+ new ThreadPoolExecutor(
+ 1,
+ poolSize,
+ 10,
+ TimeUnit.MINUTES,
+ new ArrayBlockingQueue<Runnable>(poolSize),
+ new ThreadFactoryBuilder()
+ .setNameFormat("ChangeUpdate-%d")
+ .setDaemon(true)
+ .build(),
+ new ThreadPoolExecutor.CallerRunsPolicy()))));
}
}
diff --git a/java/com/google/gerrit/server/git/WorkQueue.java b/java/com/google/gerrit/server/git/WorkQueue.java
index a2c12df..a7336f0 100644
--- a/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/java/com/google/gerrit/server/git/WorkQueue.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.git;
+import static java.util.stream.Collectors.toList;
+
import com.google.common.base.CaseFormat;
import com.google.common.base.Supplier;
import com.google.common.flogger.FluentLogger;
@@ -24,7 +26,8 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.ScheduleConfig.Schedule;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContext;
+import com.google.gerrit.server.logging.LoggingContextAwareRunnable;
import com.google.gerrit.server.util.IdGenerator;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -43,6 +46,7 @@
import java.util.concurrent.Future;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
@@ -166,12 +170,11 @@
if (threadPriority != Thread.NORM_PRIORITY) {
ThreadFactory parent = executor.getThreadFactory();
executor.setThreadFactory(
- new LoggingContextAwareThreadFactory(
- task -> {
- Thread t = parent.newThread(task);
- t.setPriority(threadPriority);
- return t;
- }));
+ task -> {
+ Thread t = parent.newThread(task);
+ t.setPriority(threadPriority);
+ return t;
+ });
}
return executor;
@@ -253,19 +256,18 @@
Executor(int corePoolSize, final String queueName) {
super(
corePoolSize,
- new LoggingContextAwareThreadFactory(
- new ThreadFactory() {
- private final ThreadFactory parent = Executors.defaultThreadFactory();
- private final AtomicInteger tid = new AtomicInteger(1);
+ new ThreadFactory() {
+ private final ThreadFactory parent = Executors.defaultThreadFactory();
+ private final AtomicInteger tid = new AtomicInteger(1);
- @Override
- public Thread newThread(Runnable task) {
- final Thread t = parent.newThread(task);
- t.setName(queueName + "-" + tid.getAndIncrement());
- t.setUncaughtExceptionHandler(LOG_UNCAUGHT_EXCEPTION);
- return t;
- }
- }));
+ @Override
+ public Thread newThread(Runnable task) {
+ final Thread t = parent.newThread(task);
+ t.setName(queueName + "-" + tid.getAndIncrement());
+ t.setUncaughtExceptionHandler(LOG_UNCAUGHT_EXCEPTION);
+ return t;
+ }
+ });
all =
new ConcurrentHashMap<>( //
@@ -277,6 +279,75 @@
}
@Override
+ public void execute(Runnable command) {
+ super.execute(LoggingContext.copy(command));
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ return super.submit(LoggingContext.copy(task));
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return super.submit(LoggingContext.copy(task), result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return super.submit(LoggingContext.copy(task));
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException {
+ return super.invokeAll(tasks.stream().map(LoggingContext::copy).collect(toList()));
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return super.invokeAll(
+ tasks.stream().map(LoggingContext::copy).collect(toList()), timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ return super.invokeAny(tasks.stream().map(LoggingContext::copy).collect(toList()));
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return super.invokeAny(
+ tasks.stream().map(LoggingContext::copy).collect(toList()), timeout, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ return super.schedule(LoggingContext.copy(command), delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ return super.schedule(LoggingContext.copy(callable), delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(
+ Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return super.scheduleAtFixedRate(LoggingContext.copy(command), initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(
+ Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ return super.scheduleWithFixedDelay(LoggingContext.copy(command), initialDelay, delay, unit);
+ }
+
+ @Override
protected void terminated() {
super.terminated();
queues.remove(this);
@@ -370,6 +441,10 @@
Task<V> task;
+ if (runnable instanceof LoggingContextAwareRunnable) {
+ runnable = ((LoggingContextAwareRunnable) runnable).unwrap();
+ }
+
if (runnable instanceof ProjectRunnable) {
task = new ProjectTask<>((ProjectRunnable) runnable, r, this, id);
} else {
diff --git a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
index b8ececb..27f6caa 100644
--- a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
@@ -23,6 +23,8 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
@@ -85,9 +87,17 @@
for (Index<Account.Id, AccountState> i : getWriteIndexes()) {
// Evict the cache to get an up-to-date value for sure.
if (accountState.isPresent()) {
- i.replace(accountState.get());
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Replacing account %d in index version %d", id.get(), i.getSchema().getVersion())) {
+ i.replace(accountState.get());
+ }
} else {
- i.delete(id);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Deleteing account %d in index version %d", id.get(), i.getSchema().getVersion())) {
+ i.delete(id);
+ }
}
}
fireAccountIndexedEvent(id.get());
diff --git a/java/com/google/gerrit/server/index/change/ChangeIndexer.java b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
index 8573862..113d340 100644
--- a/java/com/google/gerrit/server/index/change/ChangeIndexer.java
+++ b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
@@ -33,6 +33,8 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.index.IndexExecutor;
import com.google.gerrit.server.index.IndexUtils;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -214,7 +216,12 @@
private void indexImpl(ChangeData cd) throws IOException {
logger.atInfo().log("Replace change %d in index.", cd.getId().get());
for (Index<?, ChangeData> i : getWriteIndexes()) {
- i.replace(cd);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Replacing change %d in index version %d",
+ cd.getId().get(), i.getSchema().getVersion())) {
+ i.replace(cd);
+ }
}
fireChangeIndexedEvent(cd.project().get(), cd.getId().get());
}
@@ -417,7 +424,11 @@
// Implementations should not need to access the DB in order to delete a
// change ID.
for (ChangeIndex i : getWriteIndexes()) {
- i.delete(id);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Deleteing change %d in index version %d", id.get(), i.getSchema().getVersion())) {
+ i.delete(id);
+ }
}
fireChangeDeletedFromIndexEvent(id.get());
return null;
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
index 3f4c7be..28e441b 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
@@ -23,6 +23,8 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
@@ -85,9 +87,17 @@
for (Index<AccountGroup.UUID, InternalGroup> i : getWriteIndexes()) {
if (internalGroup.isPresent()) {
- i.replace(internalGroup.get());
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Replacing group %s in index version %d", uuid.get(), i.getSchema().getVersion())) {
+ i.replace(internalGroup.get());
+ }
} else {
- i.delete(uuid);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Deleting group %s in index version %d", uuid.get(), i.getSchema().getVersion())) {
+ i.delete(uuid);
+ }
}
}
fireGroupIndexedEvent(uuid.get());
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
index f5bf8b5..1ec5d55 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
@@ -24,6 +24,8 @@
import com.google.gerrit.index.project.ProjectIndexCollection;
import com.google.gerrit.index.project.ProjectIndexer;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.assistedinject.Assisted;
@@ -75,13 +77,23 @@
logger.atInfo().log("Replace project %s in index", nameKey.get());
ProjectData projectData = projectState.toProjectData();
for (ProjectIndex i : getWriteIndexes()) {
- i.replace(projectData);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Replacing project %s in index version %d",
+ nameKey.get(), i.getSchema().getVersion())) {
+ i.replace(projectData);
+ }
}
fireProjectIndexedEvent(nameKey.get());
} else {
logger.atInfo().log("Delete project %s from index", nameKey.get());
for (ProjectIndex i : getWriteIndexes()) {
- i.delete(nameKey);
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer(
+ "Deleting project %s in index version %d",
+ nameKey.get(), i.getSchema().getVersion())) {
+ i.delete(nameKey);
+ }
}
}
}
diff --git a/java/com/google/gerrit/server/logging/LoggingContext.java b/java/com/google/gerrit/server/logging/LoggingContext.java
index 2ce4c93..1e81c29 100644
--- a/java/com/google/gerrit/server/logging/LoggingContext.java
+++ b/java/com/google/gerrit/server/logging/LoggingContext.java
@@ -16,6 +16,7 @@
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.backend.Tags;
+import java.util.concurrent.Callable;
import java.util.logging.Level;
/**
@@ -42,6 +43,20 @@
return INSTANCE;
}
+ public static Runnable copy(Runnable runnable) {
+ if (runnable instanceof LoggingContextAwareRunnable) {
+ return runnable;
+ }
+ return new LoggingContextAwareRunnable(runnable);
+ }
+
+ public static <T> Callable<T> copy(Callable<T> callable) {
+ if (callable instanceof LoggingContextAwareCallable) {
+ return callable;
+ }
+ return new LoggingContextAwareCallable<>(callable);
+ }
+
@Override
public boolean shouldForceLogging(String loggerName, Level level, boolean isEnabled) {
return isLoggingForced();
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareCallable.java b/java/com/google/gerrit/server/logging/LoggingContextAwareCallable.java
new file mode 100644
index 0000000..6aff5c4
--- /dev/null
+++ b/java/com/google/gerrit/server/logging/LoggingContextAwareCallable.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.logging;
+
+import com.google.common.collect.ImmutableSetMultimap;
+import java.util.concurrent.Callable;
+
+/**
+ * Wrapper for a {@link Callable} that copies the {@link LoggingContext} from the current thread to
+ * the thread that executes the callable.
+ *
+ * <p>The state of the logging context that is copied to the thread that executes the callable is
+ * fixed at the creation time of this wrapper. If the callable is submitted to an executor and is
+ * executed later this means that changes that are done to the logging context in between creating
+ * and executing the callable do not apply.
+ *
+ * <p>See {@link LoggingContextAwareRunnable} for an example.
+ *
+ * @see LoggingContextAwareRunnable
+ */
+class LoggingContextAwareCallable<T> implements Callable<T> {
+ private final Callable<T> callable;
+ private final Thread callingThread;
+ private final ImmutableSetMultimap<String, String> tags;
+ private final boolean forceLogging;
+
+ LoggingContextAwareCallable(Callable<T> callable) {
+ this.callable = callable;
+ this.callingThread = Thread.currentThread();
+ this.tags = LoggingContext.getInstance().getTagsAsMap();
+ this.forceLogging = LoggingContext.getInstance().isLoggingForced();
+ }
+
+ @Override
+ public T call() throws Exception {
+ if (callingThread.equals(Thread.currentThread())) {
+ // propagation of logging context is not needed
+ return callable.call();
+ }
+
+ // propagate logging context
+ LoggingContext loggingCtx = LoggingContext.getInstance();
+ ImmutableSetMultimap<String, String> oldTags = loggingCtx.getTagsAsMap();
+ boolean oldForceLogging = loggingCtx.isLoggingForced();
+ loggingCtx.setTags(tags);
+ loggingCtx.forceLogging(forceLogging);
+ try {
+ return callable.call();
+ } finally {
+ loggingCtx.setTags(oldTags);
+ loggingCtx.forceLogging(oldForceLogging);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareExecutorService.java b/java/com/google/gerrit/server/logging/LoggingContextAwareExecutorService.java
new file mode 100644
index 0000000..17e152e
--- /dev/null
+++ b/java/com/google/gerrit/server/logging/LoggingContextAwareExecutorService.java
@@ -0,0 +1,110 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.logging;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * An {@link ExecutorService} that copies the {@link LoggingContext} on executing a {@link Runnable}
+ * to the executing thread.
+ */
+public class LoggingContextAwareExecutorService implements ExecutorService {
+ private final ExecutorService executorService;
+
+ public LoggingContextAwareExecutorService(ExecutorService executorService) {
+ this.executorService = executorService;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executorService.execute(LoggingContext.copy(command));
+ }
+
+ @Override
+ public void shutdown() {
+ executorService.shutdown();
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return executorService.shutdownNow();
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return executorService.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return executorService.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ return executorService.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ return executorService.submit(LoggingContext.copy(task));
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return executorService.submit(LoggingContext.copy(task), result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return executorService.submit(LoggingContext.copy(task));
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException {
+ return executorService.invokeAll(tasks.stream().map(LoggingContext::copy).collect(toList()));
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return executorService.invokeAll(
+ tasks.stream().map(LoggingContext::copy).collect(toList()), timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ return executorService.invokeAny(tasks.stream().map(LoggingContext::copy).collect(toList()));
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return executorService.invokeAny(
+ tasks.stream().map(LoggingContext::copy).collect(toList()), timeout, unit);
+ }
+}
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java b/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java
new file mode 100644
index 0000000..0bd7d00
--- /dev/null
+++ b/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java
@@ -0,0 +1,89 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.logging;
+
+import com.google.common.collect.ImmutableSetMultimap;
+
+/**
+ * Wrapper for a {@link Runnable} that copies the {@link LoggingContext} from the current thread to
+ * the thread that executes the runnable.
+ *
+ * <p>The state of the logging context that is copied to the thread that executes the runnable is
+ * fixed at the creation time of this wrapper. If the runnable is submitted to an executor and is
+ * executed later this means that changes that are done to the logging context in between creating
+ * and executing the runnable do not apply.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * try (TraceContext traceContext = TraceContext.newTrace(true, ...)) {
+ * executor
+ * .submit(new LoggingContextAwareRunnable(
+ * () -> {
+ * // Tracing is enabled since the runnable is created within the TraceContext.
+ * // Tracing is even enabled if the executor runs the runnable only after the
+ * // TraceContext was closed.
+ *
+ * // The tag "foo=bar" is not set, since it was added to the logging context only
+ * // after this runnable was created.
+ *
+ * // do stuff
+ * }))
+ * .get();
+ * traceContext.addTag("foo", "bar");
+ * }
+ * </pre>
+ *
+ * @see LoggingContextAwareCallable
+ */
+public class LoggingContextAwareRunnable implements Runnable {
+ private final Runnable runnable;
+ private final Thread callingThread;
+ private final ImmutableSetMultimap<String, String> tags;
+ private final boolean forceLogging;
+
+ LoggingContextAwareRunnable(Runnable runnable) {
+ this.runnable = runnable;
+ this.callingThread = Thread.currentThread();
+ this.tags = LoggingContext.getInstance().getTagsAsMap();
+ this.forceLogging = LoggingContext.getInstance().isLoggingForced();
+ }
+
+ public Runnable unwrap() {
+ return runnable;
+ }
+
+ @Override
+ public void run() {
+ if (callingThread.equals(Thread.currentThread())) {
+ // propagation of logging context is not needed
+ runnable.run();
+ return;
+ }
+
+ // propagate logging context
+ LoggingContext loggingCtx = LoggingContext.getInstance();
+ ImmutableSetMultimap<String, String> oldTags = loggingCtx.getTagsAsMap();
+ boolean oldForceLogging = loggingCtx.isLoggingForced();
+ loggingCtx.setTags(tags);
+ loggingCtx.forceLogging(forceLogging);
+ try {
+ runnable.run();
+ } finally {
+ loggingCtx.setTags(oldTags);
+ loggingCtx.forceLogging(oldForceLogging);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareScheduledExecutorService.java b/java/com/google/gerrit/server/logging/LoggingContextAwareScheduledExecutorService.java
new file mode 100644
index 0000000..e17a91e
--- /dev/null
+++ b/java/com/google/gerrit/server/logging/LoggingContextAwareScheduledExecutorService.java
@@ -0,0 +1,59 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.logging;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ScheduledExecutorService} that copies the {@link LoggingContext} on executing a {@link
+ * Runnable} to the executing thread.
+ */
+public class LoggingContextAwareScheduledExecutorService extends LoggingContextAwareExecutorService
+ implements ScheduledExecutorService {
+ private final ScheduledExecutorService scheduledExecutorService;
+
+ public LoggingContextAwareScheduledExecutorService(
+ ScheduledExecutorService scheduledExecutorService) {
+ super(scheduledExecutorService);
+ this.scheduledExecutorService = scheduledExecutorService;
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ return scheduledExecutorService.schedule(LoggingContext.copy(command), delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ return scheduledExecutorService.schedule(LoggingContext.copy(callable), delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(
+ Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return scheduledExecutorService.scheduleAtFixedRate(
+ LoggingContext.copy(command), initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(
+ Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ return scheduledExecutorService.scheduleWithFixedDelay(
+ LoggingContext.copy(command), initialDelay, delay, unit);
+ }
+}
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareThreadFactory.java b/java/com/google/gerrit/server/logging/LoggingContextAwareThreadFactory.java
deleted file mode 100644
index 05ff0d3..0000000
--- a/java/com/google/gerrit/server/logging/LoggingContextAwareThreadFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.logging;
-
-import com.google.common.collect.ImmutableSetMultimap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-
-/**
- * ThreadFactory that copies the logging context of the current thread to any new thread that is
- * created by this ThreadFactory.
- */
-public class LoggingContextAwareThreadFactory implements ThreadFactory {
- private final ThreadFactory parentThreadFactory;
-
- public LoggingContextAwareThreadFactory() {
- this.parentThreadFactory = Executors.defaultThreadFactory();
- }
-
- public LoggingContextAwareThreadFactory(ThreadFactory parentThreadFactory) {
- this.parentThreadFactory = parentThreadFactory;
- }
-
- @Override
- public Thread newThread(Runnable r) {
- Thread callingThread = Thread.currentThread();
- ImmutableSetMultimap<String, String> tags = LoggingContext.getInstance().getTagsAsMap();
- boolean forceLogging = LoggingContext.getInstance().isLoggingForced();
- return parentThreadFactory.newThread(
- () -> {
- if (callingThread.equals(Thread.currentThread())) {
- // propagation of logging context is not needed
- r.run();
- return;
- }
-
- // propagate logging context
- LoggingContext loggingCtx = LoggingContext.getInstance();
- loggingCtx.setTags(tags);
- loggingCtx.forceLogging(forceLogging);
- try {
- r.run();
- } finally {
- loggingCtx.clearTags();
- loggingCtx.forceLogging(false);
- }
- });
- }
-}
diff --git a/java/com/google/gerrit/server/logging/TraceContext.java b/java/com/google/gerrit/server/logging/TraceContext.java
index 5397077..977baa5 100644
--- a/java/com/google/gerrit/server/logging/TraceContext.java
+++ b/java/com/google/gerrit/server/logging/TraceContext.java
@@ -16,11 +16,15 @@
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* TraceContext that allows to set logging tags and enforce logging.
@@ -43,8 +47,9 @@
* </pre>
*
* <p>The logging tags and the force logging flag are stored in the {@link LoggingContext}. {@link
- * LoggingContextAwareThreadFactory} ensures that the logging context is automatically copied to
- * background threads.
+ * LoggingContextAwareExecutorService}, {@link LoggingContextAwareScheduledExecutorService} and the
+ * executor in {@link com.google.gerrit.server.git.WorkQueue} ensure that the logging context is
+ * automatically copied to background threads.
*
* <p>On close of the trace context newly set tags are unset. Force logging is disabled on close if
* it got enabled while the trace context was open.
@@ -148,6 +153,75 @@
void accept(String tagName, String traceId);
}
+ /**
+ * Opens a new timer that logs the time for an operation if request tracing is enabled.
+ *
+ * <p>If request tracing is not enabled this is a no-op.
+ *
+ * @param message the message
+ * @return the trace timer
+ */
+ public static TraceTimer newTimer(String message) {
+ return new TraceTimer(message);
+ }
+
+ /**
+ * Opens a new timer that logs the time for an operation if request tracing is enabled.
+ *
+ * <p>If request tracing is not enabled this is a no-op.
+ *
+ * @param format the message format string
+ * @param arg argument for the message
+ * @return the trace timer
+ */
+ public static TraceTimer newTimer(String format, Object arg) {
+ return new TraceTimer(format, arg);
+ }
+
+ /**
+ * Opens a new timer that logs the time for an operation if request tracing is enabled.
+ *
+ * <p>If request tracing is not enabled this is a no-op.
+ *
+ * @param format the message format string
+ * @param arg1 first argument for the message
+ * @param arg2 second argument for the message
+ * @return the trace timer
+ */
+ public static TraceTimer newTimer(String format, Object arg1, Object arg2) {
+ return new TraceTimer(format, arg1, arg2);
+ }
+
+ public static class TraceTimer implements AutoCloseable {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private final Consumer<Long> logFn;
+ private final Stopwatch stopwatch;
+
+ private TraceTimer(String message) {
+ this(elapsedMs -> logger.atFine().log(message + " (%d ms)", elapsedMs));
+ }
+
+ private TraceTimer(String format, @Nullable Object arg) {
+ this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg, elapsedMs));
+ }
+
+ private TraceTimer(String format, @Nullable Object arg1, @Nullable Object arg2) {
+ this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg1, arg2, elapsedMs));
+ }
+
+ private TraceTimer(Consumer<Long> logFn) {
+ this.logFn = logFn;
+ this.stopwatch = Stopwatch.createStarted();
+ }
+
+ @Override
+ public void close() {
+ stopwatch.stop();
+ logFn.accept(stopwatch.elapsed(TimeUnit.MILLISECONDS));
+ }
+ }
+
// Table<TAG_NAME, TAG_VALUE, REMOVE_ON_CLOSE>
private final Table<String, String, Boolean> tags = HashBasedTable.create();
diff --git a/java/com/google/gerrit/server/patch/DiffExecutorModule.java b/java/com/google/gerrit/server/patch/DiffExecutorModule.java
index f3776e0..eb6a280 100644
--- a/java/com/google/gerrit/server/patch/DiffExecutorModule.java
+++ b/java/com/google/gerrit/server/patch/DiffExecutorModule.java
@@ -15,7 +15,7 @@
package com.google.gerrit.server.patch;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
@@ -32,11 +32,8 @@
@Singleton
@DiffExecutor
public ExecutorService createDiffExecutor() {
- return Executors.newCachedThreadPool(
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("Diff-%d")
- .setDaemon(true)
- .build());
+ return new LoggingContextAwareExecutorService(
+ Executors.newCachedThreadPool(
+ new ThreadFactoryBuilder().setNameFormat("Diff-%d").setDaemon(true).build()));
}
}
diff --git a/java/com/google/gerrit/server/project/ProjectCacheClock.java b/java/com/google/gerrit/server/project/ProjectCacheClock.java
index 188ee08..eb451fd 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheClock.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheClock.java
@@ -18,7 +18,7 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareScheduledExecutorService;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.concurrent.Executors;
@@ -54,14 +54,14 @@
// Start with generation 1 (to avoid magic 0 below).
generation.set(1);
executor =
- Executors.newScheduledThreadPool(
- 1,
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("ProjectCacheClock-%d")
- .setDaemon(true)
- .setPriority(Thread.MIN_PRIORITY)
- .build());
+ new LoggingContextAwareScheduledExecutorService(
+ Executors.newScheduledThreadPool(
+ 1,
+ new ThreadFactoryBuilder()
+ .setNameFormat("ProjectCacheClock-%d")
+ .setDaemon(true)
+ .setPriority(Thread.MIN_PRIORITY)
+ .build()));
@SuppressWarnings("unused") // Runnable already handles errors
Future<?> possiblyIgnoredError =
executor.scheduleAtFixedRate(
diff --git a/java/com/google/gerrit/server/project/ProjectCacheWarmer.java b/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
index adfaf62..10cf2de 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
@@ -19,11 +19,11 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.lib.Config;
@@ -44,13 +44,11 @@
public void start() {
int cpus = Runtime.getRuntime().availableProcessors();
if (config.getBoolean("cache", "projects", "loadOnStartup", false)) {
- ThreadPoolExecutor pool =
- new ScheduledThreadPoolExecutor(
- config.getInt("cache", "projects", "loadThreads", cpus),
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("ProjectCacheLoader-%d")
- .build());
+ ExecutorService pool =
+ new LoggingContextAwareExecutorService(
+ new ScheduledThreadPoolExecutor(
+ config.getInt("cache", "projects", "loadThreads", cpus),
+ new ThreadFactoryBuilder().setNameFormat("ProjectCacheLoader-%d").build()));
Thread scheduler =
new Thread(
() -> {
diff --git a/java/com/google/gerrit/server/update/RetryHelper.java b/java/com/google/gerrit/server/update/RetryHelper.java
index 132c04b..10e3455 100644
--- a/java/com/google/gerrit/server/update/RetryHelper.java
+++ b/java/com/google/gerrit/server/update/RetryHelper.java
@@ -31,6 +31,7 @@
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.metrics.Counter1;
@@ -52,6 +53,8 @@
@Singleton
public class RetryHelper {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
@FunctionalInterface
public interface ChangeAction<T> {
T call(BatchUpdate.Factory batchUpdateFactory) throws Exception;
@@ -277,6 +280,9 @@
retryerBuilder.withRetryListener(listener);
return executeWithTimeoutCount(actionType, action, retryerBuilder.build());
} finally {
+ if (listener.getAttemptCount() > 1) {
+ logger.atFine().log("%s was attempted %d times", actionType, listener.getAttemptCount());
+ }
metrics.attemptCounts.record(actionType, listener.getAttemptCount());
}
}
diff --git a/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index 68ea7bb..1fdf7d8 100644
--- a/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -22,7 +22,7 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.logging.LoggingContextAwareThreadFactory;
+import com.google.gerrit.server.logging.LoggingContextAwareExecutorService;
import com.google.gerrit.sshd.SshScope.Context;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
@@ -78,12 +78,12 @@
int threads = cfg.getInt("sshd", "commandStartThreads", 2);
startExecutor = workQueue.createQueue(threads, "SshCommandStart", true);
destroyExecutor =
- Executors.newSingleThreadExecutor(
- new ThreadFactoryBuilder()
- .setThreadFactory(new LoggingContextAwareThreadFactory())
- .setNameFormat("SshCommandDestroy-%s")
- .setDaemon(true)
- .build());
+ new LoggingContextAwareExecutorService(
+ Executors.newSingleThreadExecutor(
+ new ThreadFactoryBuilder()
+ .setNameFormat("SshCommandDestroy-%s")
+ .setDaemon(true)
+ .build()));
}
@Override
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 69b8e38..b3a5e2d 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -2214,13 +2214,12 @@
// notify unrelated account as TO
String email = "user2@example.com";
- Account.Id user2Id =
- accountOperations
- .newAccount()
- .username("user2")
- .preferredEmail(email)
- .fullname("User2")
- .create();
+ accountOperations
+ .newAccount()
+ .username("user2")
+ .preferredEmail(email)
+ .fullname("User2")
+ .create();
setApiUser(user);
recommend(r.getChangeId());
setApiUser(admin);
diff --git a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
index b48d47e..137dc21 100644
--- a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
@@ -18,7 +18,9 @@
import static org.apache.http.HttpStatus.SC_CREATED;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.truth.Expect;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
@@ -27,22 +29,31 @@
import com.google.gerrit.httpd.restapi.ParameterParser;
import com.google.gerrit.httpd.restapi.RestApiServlet;
import com.google.gerrit.server.events.CommitReceivedEvent;
+import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.gerrit.server.logging.LoggingContext;
+import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.validators.ProjectCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
import java.util.List;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import org.apache.http.message.BasicHeader;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
public class TraceIT extends AbstractDaemonTest {
+ @Rule public final Expect expect = Expect.create();
+
@Inject private DynamicSet<ProjectCreationValidationListener> projectCreationValidationListeners;
@Inject private DynamicSet<CommitValidationListener> commitValidationListeners;
+ @Inject private WorkQueue workQueue;
private TraceValidatingProjectCreationValidationListener projectCreationListener;
private RegistrationHandle projectCreationListenerRegistrationHandle;
@@ -71,29 +82,90 @@
assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
assertThat(projectCreationListener.traceId).isNull();
- assertThat(projectCreationListener.foundTraceId).isFalse();
assertThat(projectCreationListener.isLoggingForced).isFalse();
}
@Test
- public void restCallWithTrace() throws Exception {
+ public void restCallWithTraceRequestParam() throws Exception {
RestResponse response =
adminRestSession.put("/projects/new2?" + ParameterParser.TRACE_PARAMETER);
assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNotNull();
assertThat(projectCreationListener.traceId).isNotNull();
- assertThat(projectCreationListener.foundTraceId).isTrue();
assertThat(projectCreationListener.isLoggingForced).isTrue();
}
@Test
- public void restCallWithTraceAndProvidedTraceId() throws Exception {
+ public void restCallWithTraceRequestParamAndProvidedTraceId() throws Exception {
RestResponse response =
adminRestSession.put("/projects/new3?" + ParameterParser.TRACE_PARAMETER + "=issue/123");
assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
- assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNotNull();
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isEqualTo("issue/123");
assertThat(projectCreationListener.traceId).isEqualTo("issue/123");
- assertThat(projectCreationListener.foundTraceId).isTrue();
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+ }
+
+ @Test
+ public void restCallWithTraceHeader() throws Exception {
+ RestResponse response =
+ adminRestSession.putWithHeader(
+ "/projects/new4", new BasicHeader(RestApiServlet.X_GERRIT_TRACE, null));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNotNull();
+ assertThat(projectCreationListener.traceId).isNotNull();
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+ }
+
+ @Test
+ public void restCallWithTraceHeaderAndProvidedTraceId() throws Exception {
+ RestResponse response =
+ adminRestSession.putWithHeader(
+ "/projects/new5", new BasicHeader(RestApiServlet.X_GERRIT_TRACE, "issue/123"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isEqualTo("issue/123");
+ assertThat(projectCreationListener.traceId).isEqualTo("issue/123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+ }
+
+ @Test
+ public void restCallWithTraceRequestParamAndTraceHeader() throws Exception {
+ // trace ID only specified by trace header
+ RestResponse response =
+ adminRestSession.putWithHeader(
+ "/projects/new6?trace", new BasicHeader(RestApiServlet.X_GERRIT_TRACE, "issue/123"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isEqualTo("issue/123");
+ assertThat(projectCreationListener.traceId).isEqualTo("issue/123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+
+ // trace ID only specified by trace request parameter
+ response =
+ adminRestSession.putWithHeader(
+ "/projects/new7?trace=issue/123", new BasicHeader(RestApiServlet.X_GERRIT_TRACE, null));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isEqualTo("issue/123");
+ assertThat(projectCreationListener.traceId).isEqualTo("issue/123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+
+ // same trace ID specified by trace header and trace request parameter
+ response =
+ adminRestSession.putWithHeader(
+ "/projects/new8?trace=issue/123",
+ new BasicHeader(RestApiServlet.X_GERRIT_TRACE, "issue/123"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isEqualTo("issue/123");
+ assertThat(projectCreationListener.traceId).isEqualTo("issue/123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+
+ // different trace IDs specified by trace header and trace request parameter
+ response =
+ adminRestSession.putWithHeader(
+ "/projects/new9?trace=issue/123",
+ new BasicHeader(RestApiServlet.X_GERRIT_TRACE, "issue/456"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeaders(RestApiServlet.X_GERRIT_TRACE))
+ .containsExactly("issue/123", "issue/456");
+ assertThat(projectCreationListener.traceIds).containsExactly("issue/123", "issue/456");
assertThat(projectCreationListener.isLoggingForced).isTrue();
}
@@ -103,7 +175,6 @@
PushOneCommit.Result r = push.to("refs/heads/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isNull();
- assertThat(commitValidationListener.foundTraceId).isFalse();
assertThat(commitValidationListener.isLoggingForced).isFalse();
}
@@ -114,7 +185,6 @@
PushOneCommit.Result r = push.to("refs/heads/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isNotNull();
- assertThat(commitValidationListener.foundTraceId).isTrue();
assertThat(commitValidationListener.isLoggingForced).isTrue();
}
@@ -125,7 +195,6 @@
PushOneCommit.Result r = push.to("refs/heads/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isEqualTo("issue/123");
- assertThat(commitValidationListener.foundTraceId).isTrue();
assertThat(commitValidationListener.isLoggingForced).isTrue();
}
@@ -135,7 +204,6 @@
PushOneCommit.Result r = push.to("refs/for/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isNull();
- assertThat(commitValidationListener.foundTraceId).isFalse();
assertThat(commitValidationListener.isLoggingForced).isFalse();
}
@@ -146,7 +214,6 @@
PushOneCommit.Result r = push.to("refs/for/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isNotNull();
- assertThat(commitValidationListener.foundTraceId).isTrue();
assertThat(commitValidationListener.isLoggingForced).isTrue();
}
@@ -157,28 +224,67 @@
PushOneCommit.Result r = push.to("refs/for/master");
r.assertOkStatus();
assertThat(commitValidationListener.traceId).isEqualTo("issue/123");
- assertThat(commitValidationListener.foundTraceId).isTrue();
assertThat(commitValidationListener.isLoggingForced).isTrue();
}
+ @Test
+ public void workQueueCopyLoggingContext() throws Exception {
+ assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
+ assertForceLogging(false);
+ try (TraceContext traceContext = TraceContext.open().forceLogging().addTag("foo", "bar")) {
+ SortedMap<String, SortedSet<Object>> tagMap = LoggingContext.getInstance().getTags().asMap();
+ assertThat(tagMap.keySet()).containsExactly("foo");
+ assertThat(tagMap.get("foo")).containsExactly("bar");
+ assertForceLogging(true);
+
+ workQueue
+ .createQueue(1, "test-queue")
+ .submit(
+ () -> {
+ // Verify that the tags and force logging flag have been propagated to the new
+ // thread.
+ SortedMap<String, SortedSet<Object>> threadTagMap =
+ LoggingContext.getInstance().getTags().asMap();
+ expect.that(threadTagMap.keySet()).containsExactly("foo");
+ expect.that(threadTagMap.get("foo")).containsExactly("bar");
+ expect
+ .that(LoggingContext.getInstance().shouldForceLogging(null, null, false))
+ .isTrue();
+ })
+ .get();
+
+ // Verify that tags and force logging flag in the outer thread are still set.
+ tagMap = LoggingContext.getInstance().getTags().asMap();
+ assertThat(tagMap.keySet()).containsExactly("foo");
+ assertThat(tagMap.get("foo")).containsExactly("bar");
+ assertForceLogging(true);
+ }
+ assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
+ assertForceLogging(false);
+ }
+
+ private void assertForceLogging(boolean expected) {
+ assertThat(LoggingContext.getInstance().shouldForceLogging(null, null, false))
+ .isEqualTo(expected);
+ }
+
private static class TraceValidatingProjectCreationValidationListener
implements ProjectCreationValidationListener {
String traceId;
- Boolean foundTraceId;
+ ImmutableSet<String> traceIds;
Boolean isLoggingForced;
@Override
public void validateNewProject(CreateProjectArgs args) throws ValidationException {
this.traceId =
Iterables.getFirst(LoggingContext.getInstance().getTagsAsMap().get("TRACE_ID"), null);
- this.foundTraceId = traceId != null;
+ this.traceIds = LoggingContext.getInstance().getTagsAsMap().get("TRACE_ID");
this.isLoggingForced = LoggingContext.getInstance().shouldForceLogging(null, null, false);
}
}
private static class TraceValidatingCommitValidationListener implements CommitValidationListener {
String traceId;
- Boolean foundTraceId;
Boolean isLoggingForced;
@Override
@@ -186,7 +292,6 @@
throws CommitValidationException {
this.traceId =
Iterables.getFirst(LoggingContext.getInstance().getTagsAsMap().get("TRACE_ID"), null);
- this.foundTraceId = traceId != null;
this.isLoggingForced = LoggingContext.getInstance().shouldForceLogging(null, null, false);
return ImmutableList.of();
}
diff --git a/javatests/com/google/gerrit/server/logging/LoggingContextAwareExecutorServiceTest.java b/javatests/com/google/gerrit/server/logging/LoggingContextAwareExecutorServiceTest.java
new file mode 100644
index 0000000..5117c01
--- /dev/null
+++ b/javatests/com/google/gerrit/server/logging/LoggingContextAwareExecutorServiceTest.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.logging;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.truth.Expect;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class LoggingContextAwareExecutorServiceTest {
+ @Rule public final Expect expect = Expect.create();
+
+ @Test
+ public void loggingContextPropagationToBackgroundThread() throws Exception {
+ assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
+ assertForceLogging(false);
+ try (TraceContext traceContext = TraceContext.open().forceLogging().addTag("foo", "bar")) {
+ SortedMap<String, SortedSet<Object>> tagMap = LoggingContext.getInstance().getTags().asMap();
+ assertThat(tagMap.keySet()).containsExactly("foo");
+ assertThat(tagMap.get("foo")).containsExactly("bar");
+ assertForceLogging(true);
+
+ ExecutorService executor =
+ new LoggingContextAwareExecutorService(Executors.newFixedThreadPool(1));
+ executor
+ .submit(
+ () -> {
+ // Verify that the tags and force logging flag have been propagated to the new
+ // thread.
+ SortedMap<String, SortedSet<Object>> threadTagMap =
+ LoggingContext.getInstance().getTags().asMap();
+ expect.that(threadTagMap.keySet()).containsExactly("foo");
+ expect.that(threadTagMap.get("foo")).containsExactly("bar");
+ expect
+ .that(LoggingContext.getInstance().shouldForceLogging(null, null, false))
+ .isTrue();
+ })
+ .get();
+
+ // Verify that tags and force logging flag in the outer thread are still set.
+ tagMap = LoggingContext.getInstance().getTags().asMap();
+ assertThat(tagMap.keySet()).containsExactly("foo");
+ assertThat(tagMap.get("foo")).containsExactly("bar");
+ assertForceLogging(true);
+ }
+ assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
+ assertForceLogging(false);
+ }
+
+ private void assertForceLogging(boolean expected) {
+ assertThat(LoggingContext.getInstance().shouldForceLogging(null, null, false))
+ .isEqualTo(expected);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/logging/LoggingContextAwareThreadFactoryTest.java b/javatests/com/google/gerrit/server/logging/LoggingContextAwareThreadFactoryTest.java
deleted file mode 100644
index 1164e27..0000000
--- a/javatests/com/google/gerrit/server/logging/LoggingContextAwareThreadFactoryTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.logging;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.truth.Expect;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import org.junit.Rule;
-import org.junit.Test;
-
-public class LoggingContextAwareThreadFactoryTest {
- @Rule public final Expect expect = Expect.create();
-
- @Test
- public void loggingContextPropagationToNewThread() throws Exception {
- assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
- assertForceLogging(false);
- try (TraceContext traceContext = TraceContext.open().forceLogging().addTag("foo", "bar")) {
- SortedMap<String, SortedSet<Object>> tagMap = LoggingContext.getInstance().getTags().asMap();
- assertThat(tagMap.keySet()).containsExactly("foo");
- assertThat(tagMap.get("foo")).containsExactly("bar");
- assertForceLogging(true);
-
- Thread thread =
- new LoggingContextAwareThreadFactory(r -> new Thread(r, "test-thread"))
- .newThread(
- () -> {
- // Verify that the tags and force logging flag have been propagated to the new
- // thread.
- SortedMap<String, SortedSet<Object>> threadTagMap =
- LoggingContext.getInstance().getTags().asMap();
- expect.that(threadTagMap.keySet()).containsExactly("foo");
- expect.that(threadTagMap.get("foo")).containsExactly("bar");
- expect
- .that(LoggingContext.getInstance().shouldForceLogging(null, null, false))
- .isTrue();
- });
-
- // Execute in background.
- thread.start();
- thread.join();
-
- // Verify that tags and force logging flag in the outer thread are still set.
- tagMap = LoggingContext.getInstance().getTags().asMap();
- assertThat(tagMap.keySet()).containsExactly("foo");
- assertThat(tagMap.get("foo")).containsExactly("bar");
- assertForceLogging(true);
- }
- assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
- assertForceLogging(false);
- }
-
- @Test
- public void loggingContextPropagationToSameThread() throws Exception {
- assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
- assertForceLogging(false);
- try (TraceContext traceContext = TraceContext.open().forceLogging().addTag("foo", "bar")) {
- SortedMap<String, SortedSet<Object>> tagMap = LoggingContext.getInstance().getTags().asMap();
- assertThat(tagMap.keySet()).containsExactly("foo");
- assertThat(tagMap.get("foo")).containsExactly("bar");
- assertForceLogging(true);
-
- Thread thread =
- new LoggingContextAwareThreadFactory()
- .newThread(
- () -> {
- // Verify that the tags and force logging flag have been propagated to the new
- // thread.
- SortedMap<String, SortedSet<Object>> threadTagMap =
- LoggingContext.getInstance().getTags().asMap();
- expect.that(threadTagMap.keySet()).containsExactly("foo");
- expect.that(threadTagMap.get("foo")).containsExactly("bar");
- expect
- .that(LoggingContext.getInstance().shouldForceLogging(null, null, false))
- .isTrue();
- });
-
- // Execute in the same thread.
- thread.run();
-
- // Verify that tags and force logging flag in the outer thread are still set.
- tagMap = LoggingContext.getInstance().getTags().asMap();
- assertThat(tagMap.keySet()).containsExactly("foo");
- assertThat(tagMap.get("foo")).containsExactly("bar");
- assertForceLogging(true);
- }
- assertThat(LoggingContext.getInstance().getTags().isEmpty()).isTrue();
- assertForceLogging(false);
- }
-
- private void assertForceLogging(boolean expected) {
- assertThat(LoggingContext.getInstance().shouldForceLogging(null, null, false))
- .isEqualTo(expected);
- }
-}
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index 6ada5bd..7191901 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -1,6 +1,6 @@
load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL", "maven_jar")
-_JGIT_VERS = "5.0.2.201807311906-r"
+_JGIT_VERS = "5.0.3.201809091024-r"
_DOC_VERS = _JGIT_VERS # Set to _JGIT_VERS unless using a snapshot
@@ -40,28 +40,28 @@
name = "jgit-lib",
artifact = "org.eclipse.jgit:org.eclipse.jgit:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "a81d7c8d153a8a744b6be1d9c6d698270beec1c0",
- src_sha1 = "c89f8f38cebaf75d13f9b2f7a1da71206d8c38f7",
+ sha1 = "0afec2df3ff8835bc4d5c279d14fad0daae6dd93",
+ src_sha1 = "e2c978064e2a46b260bbda0d8c393ed741046420",
unsign = True,
)
maven_jar(
name = "jgit-servlet",
artifact = "org.eclipse.jgit:org.eclipse.jgit.http.server:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "ab3d0c85bc2008da513c1127ab4acf3df8ef414e",
+ sha1 = "8fb0f9b6c38ac6fce60f2ead740e03dd79c3c288",
unsign = True,
)
maven_jar(
name = "jgit-archive",
artifact = "org.eclipse.jgit:org.eclipse.jgit.archive:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "ba6e0aaf3f733f2f460e227145526e1737ca160f",
+ sha1 = "72a157ce261f3eb938d9e0ee83d7c9700aa7d736",
)
maven_jar(
name = "jgit-junit",
artifact = "org.eclipse.jgit:org.eclipse.jgit.junit:" + _JGIT_VERS,
repository = _JGIT_REPO,
- sha1 = "fe28963520e19c918eb26747e678ec9772ba800f",
+ sha1 = "eb430358d96dedd923e4075cd54a7db4cab51ca2",
unsign = True,
)
diff --git a/plugins/hooks b/plugins/hooks
index ca64db3..cc74144 160000
--- a/plugins/hooks
+++ b/plugins/hooks
@@ -1 +1 @@
-Subproject commit ca64db31265e985ab3cec635d6f063b0414c45e1
+Subproject commit cc74144db755a18c5a63764a336b93ab3d1be1fe