blob: ded29e4a3bae67730ba9a9bd5a4ec1746ef52dd4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.beam.runners.dataflow.worker.counters;
import static org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkNotNull;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.MoreObjects;
import org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.MoreObjects.ToStringHelper;
/**
* The name of a counter identifies the user-specified name, as well as the origin, the step the
* counter is associated with, and a prefix to add to the name.
*
* <p>For backwards compatibility, the {@link CounterName} will be converted to a flat name (string)
* during the migration.
*/
@AutoValue
public abstract class CounterName {
/** Returns a {@link CounterName} with the given name. */
public static CounterName named(String name) {
return create(
name,
"" /* origin */,
"" /* stepName */,
"" /* prefix */,
null /* contextOriginalName */,
null /* contextSystemName */,
null /* originalRequestingStepName */,
null /* inputIndex */);
}
/** Returns a msecs {@link CounterName}. */
public static CounterName msecs(String name) {
return named(name + "-msecs");
}
/** Returns a {@link CounterName} identical to this, but with the given origin. */
public CounterName withOrigin(String origin) {
return create(
name(),
origin,
stepName(),
prefix(),
contextOriginalName(),
contextSystemName(),
originalRequestingStepName(),
inputIndex());
}
/** Returns a {@link CounterName} identical to this, but with the given step name. */
public CounterName withStepName(String stepName) {
return create(
name(),
origin(),
stepName,
prefix(),
contextOriginalName(),
contextSystemName(),
originalRequestingStepName(),
inputIndex());
}
/** Returns a {@link CounterName} identical to this, but with the given prefix. */
public CounterName withPrefix(String prefix) {
return create(
name(),
origin(),
stepName(),
prefix,
contextOriginalName(),
contextSystemName(),
originalRequestingStepName(),
inputIndex());
}
/**
* Returns a {@link CounterName} identical to this, but with the {@code originalName} from a
* {@link NameContext}.
*/
public CounterName withOriginalName(NameContext context) {
return create(
name(),
origin(),
stepName(),
prefix(),
checkNotNull(context.originalName(), "Expected original name in context %s", context),
contextSystemName(),
originalRequestingStepName(),
inputIndex());
}
/**
* Returns a {@link CounterName} identical to this, but with the {@code originalName} from a
* {@link String}.
*/
public CounterName withOriginalName(String originalName) {
return create(
name(),
origin(),
stepName(),
prefix(),
checkNotNull(originalName, "Expected original name in string %s", originalName),
contextSystemName(),
originalRequestingStepName(),
inputIndex());
}
/**
* Returns a {@link CounterName} identical to this, but with the {@code systemName} from a {@link
* NameContext}.
*/
public CounterName withSystemName(NameContext context) {
return create(
name(),
origin(),
stepName(),
prefix(),
contextOriginalName(),
checkNotNull(context.systemName(), "Expected system name in context %s", context),
originalRequestingStepName(),
inputIndex());
}
/**
* Returns a {@link CounterName} identical to this, but with the {@code
* originalRequestingStepName}
*/
public CounterName withOriginalRequestingStepName(String originalRequestingStepName) {
return create(
name(),
origin(),
stepName(),
prefix(),
contextOriginalName(),
contextSystemName(),
checkNotNull(originalRequestingStepName, "Expected a requesting step name"),
inputIndex());
}
public CounterName withInputIndex(Integer inputIndex) {
return create(
name(),
origin(),
stepName(),
prefix(),
contextOriginalName(),
contextSystemName(),
originalRequestingStepName(),
checkNotNull(inputIndex, "Expected an input index"));
}
static CounterName create(
String name,
String origin,
String stepName,
String prefix,
String contextOriginalName,
String contextSystemName,
String originalRequestingStepName,
Integer inputIndex) {
return new AutoValue_CounterName(
checkNotNull(name, "Name is required for CounterName"),
checkNotNull(origin, "Origin is required for CounterName"),
checkNotNull(stepName, "StepName is required for CounterName"),
checkNotNull(prefix, "Prefix is required for CounterName"),
contextOriginalName,
contextSystemName,
originalRequestingStepName,
inputIndex);
}
/**
* Name of the counter.
*
* <p>For example, process-msecs, ElementCount.
*/
public abstract String name();
/**
* Origin (namespace) of counter name.
*
* <p>For example, "user" for user-defined counters. It is empty for counters defined by the SDK
* or the runner.
*/
public abstract String origin();
/**
* System defined step name or the named-output of a step.
*
* <p>For example, {@code s1} or {@code s2.out}. It may be empty when counters don't associate
* with step names.
*/
public abstract String stepName();
/**
* Prefix of group of counters.
*
* <p>It is empty when counters don't have general prefixes.
*/
public abstract String prefix();
/** An optional {@code contextOriginalName}. */
@Nullable
public abstract String contextOriginalName();
/** An optional {@code contextSystemName}. */
@Nullable
public abstract String contextSystemName();
/** An optional {@code originalRequestingStepName}. */
@Nullable
public abstract String originalRequestingStepName();
/**
* An optional identifier of a PCollection by index in input list received by step.
*
* <p>A CounterName with inputIndex set to 1, and stepName set to 's1' would declare a counter
* associated to s1's first side input.
*/
@Nullable
public abstract Integer inputIndex();
/**
* Flat name is suitable only for hashing.
*
* <p>It is null before {@link #getFlatName()} is called. TODO: this can be replaced
* with @Memoized when v1.4 auto.value is released
*/
private volatile String flatName;
public String getFlatName() {
if (flatName == null) {
synchronized (this) {
if (flatName == null) {
flatName = toString();
}
}
}
return flatName;
}
public String toPrettyString() {
ToStringHelper helper = MoreObjects.toStringHelper(this);
helper.omitNullValues();
helper.add("name", name());
helper.add("origin", origin());
helper.add("prefix", prefix());
helper.add("stepName", stepName());
helper.add("contextOriginalName", contextOriginalName());
helper.add("contextSystemName", contextSystemName());
helper.add("originalRequestingStepName", originalRequestingStepName());
helper.add("inputIndex", inputIndex());
return helper.toString();
}
/**
* Pretty name is the equivalent unstructured name.
*
* <p>It is null before {@link #getPrettyName()} is called. TODO: this can be replaced
* with @Memoized when v1.4 auto.value is released
*/
private volatile String prettyName;
public String getPrettyName() {
if (prettyName == null) {
synchronized (this) {
if (prettyName == null) {
prettyName = toPrettyString();
}
}
}
return prettyName;
}
public boolean usesContextOriginalName() {
return contextOriginalName() != null;
}
public boolean usesContextSystemName() {
return contextSystemName() != null;
}
public boolean usesOriginalRequestingStepName() {
return originalRequestingStepName() != null;
}
public boolean isStructured() {
return usesContextOriginalName() || usesContextSystemName() || usesOriginalRequestingStepName();
}
}