diff --git a/temporal-sdk/src/main/java/io/temporal/failure/DefaultFailureConverter.java b/temporal-sdk/src/main/java/io/temporal/failure/DefaultFailureConverter.java index c6fb0a84c..53b601cc9 100644 --- a/temporal-sdk/src/main/java/io/temporal/failure/DefaultFailureConverter.java +++ b/temporal-sdk/src/main/java/io/temporal/failure/DefaultFailureConverter.java @@ -39,6 +39,8 @@ import io.temporal.common.converter.DataConverter; import io.temporal.common.converter.EncodedValues; import io.temporal.common.converter.FailureConverter; +import io.temporal.internal.activity.ActivityTaskHandlerImpl; +import io.temporal.internal.sync.POJOWorkflowImplementationFactory; import io.temporal.serviceclient.CheckedExceptionWrapper; import java.io.PrintWriter; import java.io.StringWriter; @@ -61,12 +63,13 @@ public final class DefaultFailureConverter implements FailureConverter { /** * Stop emitting stack trace after this line. Makes serialized stack traces more readable and - * compact as it omits most of framework level code. + * compact as it omits most of framework-level code. */ private static final ImmutableSet CUTOFF_METHOD_NAMES = - ImmutableSet.of( - "io.temporal.internal.worker.POJOActivityImplementationFactory$POJOActivityImplementation.execute", - "io.temporal.internal.sync.POJOWorkflowTaskHandler$POJOWorkflowImplementation.execute"); + ImmutableSet.builder() + .addAll(ActivityTaskHandlerImpl.ACTIVITY_HANDLER_STACKTRACE_CUTOFF) + .addAll(POJOWorkflowImplementationFactory.WORKFLOW_HANDLER_STACKTRACE_CUTOFF) + .build(); /** Used to parse a stack trace line. */ private static final Pattern TRACE_ELEMENT_PATTERN = diff --git a/temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityTaskHandlerImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityTaskHandlerImpl.java index add3ede39..471e39bc8 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityTaskHandlerImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/activity/ActivityTaskHandlerImpl.java @@ -21,6 +21,7 @@ package io.temporal.internal.activity; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; import com.uber.m3.tally.Scope; import com.uber.m3.util.ImmutableMap; import io.temporal.activity.DynamicActivity; @@ -35,6 +36,7 @@ import io.temporal.common.metadata.POJOActivityImplMetadata; import io.temporal.common.metadata.POJOActivityMethodMetadata; import io.temporal.internal.activity.ActivityTaskExecutors.ActivityTaskExecutor; +import io.temporal.internal.common.env.ReflectionUtils; import io.temporal.internal.worker.ActivityTask; import io.temporal.internal.worker.ActivityTaskHandler; import io.temporal.serviceclient.MetricsTag; @@ -46,6 +48,24 @@ import javax.annotation.Nullable; public final class ActivityTaskHandlerImpl implements ActivityTaskHandler { + public static final ImmutableSet ACTIVITY_HANDLER_STACKTRACE_CUTOFF = + ImmutableSet.builder() + // POJO + .add( + ReflectionUtils.getMethodNameForStackTraceCutoff( + ActivityTaskExecutors.POJOActivityImplementation.class, + "execute", + ActivityInfoInternal.class, + Scope.class)) + // Dynamic + .add( + ReflectionUtils.getMethodNameForStackTraceCutoff( + ActivityTaskExecutors.DynamicActivityImplementation.class, + "execute", + ActivityInfoInternal.class, + Scope.class)) + .build(); + private final DataConverter dataConverter; private final String namespace; private final String taskQueue; diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/env/ReflectionUtils.java b/temporal-sdk/src/main/java/io/temporal/internal/common/env/ReflectionUtils.java new file mode 100644 index 000000000..ff876c59e --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/env/ReflectionUtils.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material 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 io.temporal.internal.common.env; + +import com.google.common.base.Joiner; + +public final class ReflectionUtils { + private ReflectionUtils() {} + + public static String getMethodNameForStackTraceCutoff( + Class clazz, String methodName, Class... parameterTypes) throws RuntimeException { + try { + return clazz.getName() + "." + clazz.getMethod(methodName, parameterTypes).getName(); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "Reflection code that publishes the methods signatures is out of sync with actual method signatures. Class '" + + clazz.getCanonicalName() + + "' is expected to have method '" + + methodName + + "' with parameters {" + + Joiner.on(", ").join(parameterTypes) + + "}", + e); + } + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/DynamicSyncWorkflowDefinition.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/DynamicSyncWorkflowDefinition.java index 98130627d..73b55525c 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/DynamicSyncWorkflowDefinition.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/DynamicSyncWorkflowDefinition.java @@ -68,8 +68,7 @@ public Optional execute(Header header, Optional input) { return dataConverter.toPayloads(result.getResult()); } - private class RootWorkflowInboundCallsInterceptor - extends BaseRootWorkflowInboundCallsInterceptor { + class RootWorkflowInboundCallsInterceptor extends BaseRootWorkflowInboundCallsInterceptor { private DynamicWorkflow workflow; public RootWorkflowInboundCallsInterceptor(SyncWorkflowContext workflowContext) { diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/POJOWorkflowImplementationFactory.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/POJOWorkflowImplementationFactory.java index decd9ee08..977081f59 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/POJOWorkflowImplementationFactory.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/POJOWorkflowImplementationFactory.java @@ -23,6 +23,7 @@ import static io.temporal.serviceclient.CheckedExceptionWrapper.wrap; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; import io.temporal.api.common.v1.Payloads; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.api.common.v1.WorkflowType; @@ -36,6 +37,7 @@ import io.temporal.common.metadata.POJOWorkflowInterfaceMetadata; import io.temporal.common.metadata.POJOWorkflowMethodMetadata; import io.temporal.failure.CanceledFailure; +import io.temporal.internal.common.env.ReflectionUtils; import io.temporal.internal.replay.ReplayWorkflow; import io.temporal.internal.replay.ReplayWorkflowFactory; import io.temporal.internal.worker.SingleWorkerOptions; @@ -60,6 +62,20 @@ import org.slf4j.LoggerFactory; public final class POJOWorkflowImplementationFactory implements ReplayWorkflowFactory { + public static final ImmutableSet WORKFLOW_HANDLER_STACKTRACE_CUTOFF = + ImmutableSet.builder() + // POJO + .add( + ReflectionUtils.getMethodNameForStackTraceCutoff( + POJOWorkflowImplementation.class, "execute", Header.class, Optional.class)) + // Dynamic + .add( + ReflectionUtils.getMethodNameForStackTraceCutoff( + DynamicSyncWorkflowDefinition.RootWorkflowInboundCallsInterceptor.class, + "execute", + WorkflowInboundCallsInterceptor.WorkflowInput.class)) + .build(); + private static final Logger log = LoggerFactory.getLogger(POJOWorkflowImplementationFactory.class); private final WorkerInterceptor[] workerInterceptors; diff --git a/temporal-sdk/src/main/resources/temporal-sdk/reflect-config.json b/temporal-sdk/src/main/resources/temporal-sdk/reflect-config.json index d325dd6b4..5feb1219f 100644 --- a/temporal-sdk/src/main/resources/temporal-sdk/reflect-config.json +++ b/temporal-sdk/src/main/resources/temporal-sdk/reflect-config.json @@ -22,5 +22,21 @@ { "name":"com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"io.temporal.internal.activity.ActivityTaskExecutors$DynamicActivityImplementation", + "methods":[{"name":"execute","parameterTypes":["io.temporal.internal.activity.ActivityInfoInternal", "com.uber.m3.tally.Scope"] }] +}, +{ + "name":"io.temporal.internal.activity.ActivityTaskExecutors$POJOActivityImplementation", + "methods":[{"name":"execute","parameterTypes":["io.temporal.internal.activity.ActivityInfoInternal", "com.uber.m3.tally.Scope"] }] +}, +{ + "name":"io.temporal.internal.sync.POJOWorkflowImplementationFactory$POJOWorkflowImplementation", + "methods":[{"name":"execute","parameterTypes":["io.temporal.common.interceptors.Header", "java.util.Optional"] }] +}, +{ + "name":"io.temporal.internal.sync.DynamicSyncWorkflowDefinition$RootWorkflowInboundCallsInterceptor", + "methods":[{"name":"execute","parameterTypes":["io.temporal.common.interceptors.WorkflowInboundCallsInterceptor$WorkflowInput"] }] } ]