org.apache.flink.runtime.metrics.scope.ScopeFormat Maven / Gradle / Ivy
/*
* 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.flink.runtime.metrics.scope;
import org.apache.flink.metrics.CharacterFilter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.apache.flink.util.Preconditions.checkNotNull;
/**
* This class represents the format after which the "scope" (or namespace) of the various
* component metric groups is built. Component metric groups are for example
* "TaskManager", "Task", or "Operator".
*
* User defined scope formats allow users to include or exclude
* certain identifiers from the scope. The scope for metrics belonging to the "Task"
* group could for example include the task attempt number (more fine grained identification), or
* exclude it (continuity of the namespace across failure and recovery).
*/
public abstract class ScopeFormat {
private static CharacterFilter defaultFilter = new CharacterFilter() {
@Override
public String filterCharacters(String input) {
return input;
}
};
// ------------------------------------------------------------------------
// Scope Format Special Characters
// ------------------------------------------------------------------------
/**
* If the scope format starts with this character, then the parent components scope
* format will be used as a prefix.
*
*
For example, if the TaskManager's job format is {@code "*."}, and the
* TaskManager format is {@code ""}, then the job's metrics
* will have {@code "."} as their scope.
*/
public static final String SCOPE_INHERIT_PARENT = "*";
public static final String SCOPE_SEPARATOR = ".";
private static final String SCOPE_VARIABLE_PREFIX = "<";
private static final String SCOPE_VARIABLE_SUFFIX = ">";
// ------------------------------------------------------------------------
// Scope Variables
// ------------------------------------------------------------------------
public static final String SCOPE_HOST = asVariable("host");
// ----- Task Manager ----
public static final String SCOPE_TASKMANAGER_ID = asVariable("tm_id");
// ----- Job -----
public static final String SCOPE_JOB_ID = asVariable("job_id");
public static final String SCOPE_JOB_NAME = asVariable("job_name");
// ----- Task ----
public static final String SCOPE_TASK_VERTEX_ID = asVariable("task_id");
public static final String SCOPE_TASK_NAME = asVariable("task_name");
public static final String SCOPE_TASK_ATTEMPT_ID = asVariable("task_attempt_id");
public static final String SCOPE_TASK_ATTEMPT_NUM = asVariable("task_attempt_num");
public static final String SCOPE_TASK_SUBTASK_INDEX = asVariable("subtask_index");
// ----- Operator ----
public static final String SCOPE_OPERATOR_ID = asVariable("operator_id");
public static final String SCOPE_OPERATOR_NAME = asVariable("operator_name");
// ------------------------------------------------------------------------
// Scope Format Base
// ------------------------------------------------------------------------
/** The scope format. */
private final String format;
/** The format, split into components. */
private final String[] template;
private final int[] templatePos;
private final int[] valuePos;
// ------------------------------------------------------------------------
protected ScopeFormat(String format, ScopeFormat parent, String[] variables) {
checkNotNull(format, "format is null");
final String[] rawComponents = format.split("\\" + SCOPE_SEPARATOR);
// compute the template array
final boolean parentAsPrefix = rawComponents.length > 0 && rawComponents[0].equals(SCOPE_INHERIT_PARENT);
if (parentAsPrefix) {
if (parent == null) {
throw new IllegalArgumentException("Component scope format requires parent prefix (starts with '"
+ SCOPE_INHERIT_PARENT + "'), but this component has no parent (is root component).");
}
this.format = format.length() > 2 ? format.substring(2) : "";
String[] parentTemplate = parent.template;
int parentLen = parentTemplate.length;
this.template = new String[parentLen + rawComponents.length - 1];
System.arraycopy(parentTemplate, 0, this.template, 0, parentLen);
System.arraycopy(rawComponents, 1, this.template, parentLen, rawComponents.length - 1);
}
else {
this.format = format.isEmpty() ? "" : format;
this.template = rawComponents;
}
// --- compute the replacement matrix ---
// a bit of clumsy Java collections code ;-)
HashMap varToValuePos = arrayToMap(variables);
List templatePos = new ArrayList<>();
List valuePos = new ArrayList<>();
for (int i = 0; i < template.length; i++) {
final String component = template[i];
// check if that is a variable
if (component != null && component.length() >= 3 &&
component.charAt(0) == '<' && component.charAt(component.length() - 1) == '>') {
// this is a variable
Integer replacementPos = varToValuePos.get(component);
if (replacementPos != null) {
templatePos.add(i);
valuePos.add(replacementPos);
}
}
}
this.templatePos = integerListToArray(templatePos);
this.valuePos = integerListToArray(valuePos);
}
// ------------------------------------------------------------------------
public String format() {
return format;
}
protected final String[] copyTemplate() {
String[] copy = new String[template.length];
System.arraycopy(template, 0, copy, 0, template.length);
return copy;
}
protected final String[] bindVariables(String[] template, String[] values) {
final int len = templatePos.length;
for (int i = 0; i < len; i++) {
template[templatePos[i]] = values[valuePos[i]];
}
return template;
}
// ------------------------------------------------------------------------
@Override
public String toString() {
return "ScopeFormat '" + format + '\'';
}
// ------------------------------------------------------------------------
// Utilities
// ------------------------------------------------------------------------
/**
* Formats the given string to resemble a scope variable.
*
* @param scope The string to format
* @return The formatted string
*/
public static String asVariable(String scope) {
return SCOPE_VARIABLE_PREFIX + scope + SCOPE_VARIABLE_SUFFIX;
}
public static String concat(String... components) {
return concat(defaultFilter, '.', components);
}
public static String concat(CharacterFilter filter, String... components) {
return concat(filter, '.', components);
}
public static String concat(Character delimiter, String... components) {
return concat(defaultFilter, delimiter, components);
}
/**
* Concatenates the given component names separated by the delimiter character. Additionally
* the character filter is applied to all component names.
*
* @param filter Character filter to be applied to the component names
* @param delimiter Delimiter to separate component names
* @param components Array of component names
* @return The concatenated component name
*/
public static String concat(CharacterFilter filter, Character delimiter, String... components) {
StringBuilder sb = new StringBuilder();
sb.append(filter.filterCharacters(components[0]));
for (int x = 1; x < components.length; x++) {
sb.append(delimiter);
sb.append(filter.filterCharacters(components[x]));
}
return sb.toString();
}
protected static String valueOrNull(Object value) {
return (value == null || (value instanceof String && ((String) value).isEmpty())) ?
"null" : value.toString();
}
protected static HashMap arrayToMap(String[] array) {
HashMap map = new HashMap<>(array.length);
for (int i = 0; i < array.length; i++) {
map.put(array[i], i);
}
return map;
}
private static int[] integerListToArray(List list) {
int[] array = new int[list.size()];
int pos = 0;
for (Integer i : list) {
array[pos++] = i;
}
return array;
}
}