Compare commits

..

27 Commits

Author SHA1 Message Date
Zakhar Bessarab
971aecd1ae app/vlselect/logsql: skip rows without _stream reference
_stream field can be empty for the recently ingested rows because respective entry in indexdb is not yet searchable as it haven't been flushed to storage yet.
This change just skips such items in the output response to make it more consistent.

See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6042
Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-04-17 11:58:09 +04:00
Zakhar Bessarab
b4d8837917 app/vmauth: do not increment backend_errors when hitting concurrency limit (#6078)
* app/vmauth: do not increment backend_errors when hitting concurrency limit

Previously, both "vmauth_concurrent_requests_limit_reached_total" and "vmauth_user_request_backend_errors_total" were incremented.
This was based on the assumption that if concurrency limit is hit the backend must be failing to handle the request thus meaning an error.

This assumption does not work in case the endpoint can be overloaded by the misbehaving client sending too many requests within the timeframe.

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>

* Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5565

Signed-off-by: hagen1778 <roman@victoriametrics.com>

---------

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2024-04-17 09:38:19 +02:00
Github Actions
1cbaec73ad Automatic update operator docs from VictoriaMetrics/operator@99fbc98 (#6122) 2024-04-17 09:34:47 +02:00
Aliaksandr Valialkin
fff31aa8b0 docs/CHANGELOG.md: move the description for the bugfix https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6110 from v1.100.1 to the tip section
The bugfix isn't included in v1.100.1 release.

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6110
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6111
This is a follow-up for 7308bad777
2024-04-16 19:59:13 +02:00
Aliaksandr Valialkin
e3a26c0db6 lib/promscrape/discovery/consul: typo fix in the comment: enteprise -> enterprise 2024-04-16 19:34:18 +02:00
Aliaksandr Valialkin
85d09e5a2d lib/{mergeset,storage}: log deleting directories inside partitions if they are missing in parts.json
This should improve debuggability of unexpected deletion of directories inside partitions.

While at it, log the proper path to parts.json when the directory for big part is missing in the partition.
parts.json is located inside directory with small parts, and there is no parts.json file inside directory with big parts.
2024-04-16 19:11:32 +02:00
Aliaksandr Valialkin
6bcc6c938b lib/storage: improve comments inside functions responsible for creating indexes for newly registered time series 2024-04-16 19:11:32 +02:00
Zakhar Bessarab
458338afa5 docs/cluster: update cluster resizing info (#6099)
* docs/cluster: update cluster resizing info

- add example of resources distribution
- add info about how to handle uneven disk usage after adding a new storage node

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>

* Update docs/Cluster-VictoriaMetrics.md

Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>

* Update docs/Cluster-VictoriaMetrics.md

Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>

---------

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
Co-authored-by: Roman Khavronenko <roman@victoriametrics.com>
2024-04-16 15:44:05 +02:00
Github Actions
aaa18e565d Automatic update operator docs from VictoriaMetrics/operator@13f6dac (#6119) 2024-04-16 14:58:29 +02:00
hagen1778
4f55aa29db docs: mention HTTP sink configuration example for Vector
Follow-up 16eeb4e

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2024-04-16 14:07:16 +02:00
hagen1778
9064602d00 deployment/vector: add example for JSON stream config
Follow-up 16eeb4eb33

Signed-off-by: hagen1778 <roman@victoriametrics.com>
2024-04-16 13:57:54 +02:00
Devin Buhl
16eeb4eb33 victorialogs: mention vector supports http/json stream (#6114)
https://github.com/vectordotdev/vector/issues/18883#issuecomment-1771424716
2024-04-16 13:52:03 +02:00
guangwu
9dd5db2b77 app/vmctl: properly close file descriptor in verify-block action (#6106) 2024-04-16 11:33:04 +02:00
Vadim Rutkovsky
66c5fc3243 dashboards: fix typo in VictoriaLogs panel (#6102)
Comprasion -> compression
2024-04-16 09:50:46 +02:00
yudrywet
43835704b7 chore: fix some typos in comments (#6103)
Signed-off-by: yudrywet <yudeyao@yeah.net>
2024-04-16 09:48:52 +02:00
Alexander Marshalov
7308bad777 vmalert: support any status code from the range 200-299 from alertmanager as successful (#6111)
* any status code from the range 200-299 from alertmanager to vmalert is not considered an error from now on (#6110)

* add changelog
2024-04-16 09:33:11 +02:00
Github Actions
7db8ba41e7 Automatic update operator docs from VictoriaMetrics/operator@cf48a99 (#6113) 2024-04-16 09:54:29 +08:00
Dmytro Kozlov
7b20de4674 docs: fix typo in the curl command (#6109) 2024-04-15 14:29:26 +02:00
Yury Molodov
f06f55edb6 vmui/vmanomaly: integrate vmanomaly query_server (#6017)
* vmui: fix parsing of fractional values

* vmui/vmanomaly: update display logic to align with vmanomaly /query_range API

* vmui/vmanomaly: rename flag anomalyView to isAnomalyView
2024-04-15 09:25:52 +02:00
Dima Lazerka
22497c2c98 VMUI: Update builder Node version (#5908)
Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: Dzmitry Lazerka <dlazerka@gmail.com>
Co-authored-by: hagen1778 <roman@victoriametrics.com>
2024-04-15 09:07:30 +02:00
Github Actions
cba2f6dce1 Automatic update operator docs from VictoriaMetrics/operator@73a1996 (#6100) 2024-04-13 10:04:25 +08:00
hagen1778
e39a1a98f5 docs: add 1.100.1 release date
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2024-04-12 12:20:27 +02:00
Hui Wang
2123821e0f bump victoriametrics components to v1.100.1 (#6095)
* bump victoriametrics components to v1.100.1

* add one
2024-04-12 18:16:17 +08:00
Zakhar Bessarab
b8ba9ea769 docs/changelog: fix markdown formatting (#6094)
Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-04-12 17:59:21 +08:00
Zakhar Bessarab
8f457c550d docs/changelog: add update node to reset cache when upgrading to 1.100.1 (#6093)
Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-04-12 11:52:20 +02:00
hagen1778
267c28362b docs: mention that 1.100.1 isn't released yet in 1.99 section
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2024-04-11 21:46:28 +02:00
hagen1778
14f3f72829 docs: mention that 1.100.1 isn't released yet
Signed-off-by: hagen1778 <roman@victoriametrics.com>
2024-04-11 16:34:37 +02:00
60 changed files with 587 additions and 609 deletions

View File

@@ -116,7 +116,7 @@ VictoriaMetrics ecosystem contains the following components additionally to [sin
- [vmalert](https://docs.victoriametrics.com/vmalert/) - a service for processing Prometheus-compatible alerting and recording rules.
- [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/) - a tool for validating alerting and recording rules.
- [vmauth](https://docs.victoriametrics.com/vmauth/) - authorization proxy and load balancer optimized for VictoriaMetrics products.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - auhtorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - authorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmctl](https://docs.victoriametrics.com/vmctl/) - a tool for migrating and copying data between different storage systems for metrics.
- [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmrestore](https://docs.victoriametrics.com/vmrestore/) and [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/) -
tools for creating backups and restoring from backups for VictoriaMetrics data.
@@ -2417,7 +2417,7 @@ It is also possible removing [rollup result cache](#rollup-result-cache) on star
## Rollup result cache
VictoriaMetrics caches query reponses by default. This allows increasing performance for repated queries
VictoriaMetrics caches query responses by default. This allows increasing performance for repated queries
to [`/api/v1/query`](https://docs.victoriametrics.com/keyconcepts/#instant-query) and [`/api/v1/query_range`](https://docs.victoriametrics.com/keyconcepts/#range-query)
with the increasing `time`, `start` and `end` query args.

View File

@@ -48,8 +48,29 @@ func ProcessQueryRequest(w http.ResponseWriter, r *http.Request, stopCh <-chan s
}
rowsCount := len(columns[0].Values)
// skip entries with empty _stream column
// _stream is empty in case indexdb entry was not flushed to the storage yet
// skipping such entries makes the result more consistent
streamCol := 0
// fast path
// _stream column is a built-in column and it is always supposed to be at the same position
if len(columns) >= 2 && columns[1].Name == "_stream" {
streamCol = 1
} else {
for i := 1; i < len(columns); i++ {
if columns[i].Name == "_stream" {
streamCol = i
break
}
}
}
bb := blockResultPool.Get()
for rowIdx := 0; rowIdx < rowsCount; rowIdx++ {
if columns[streamCol].Values[rowIdx] == "" {
continue
}
WriteJSONRow(bb, columns, rowIdx)
}

View File

@@ -105,7 +105,7 @@ func (am *AlertManager) send(ctx context.Context, alerts []Alert, headers map[st
if *showNotifierURL {
amURL = am.addr.String()
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode/100 != 2 {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response from %q: %w", amURL, err)

View File

@@ -161,20 +161,12 @@ func processUserRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo) {
if err := ui.beginConcurrencyLimit(); err != nil {
handleConcurrencyLimitError(w, r, err)
<-concurrencyLimitCh
// Requests failed because of concurrency limit must be counted as errors,
// since this usually means the backend cannot keep up with the current load.
ui.backendErrors.Inc()
return
}
default:
concurrentRequestsLimitReached.Inc()
err := fmt.Errorf("cannot serve more than -maxConcurrentRequests=%d concurrent requests", cap(concurrencyLimitCh))
handleConcurrencyLimitError(w, r, err)
// Requests failed because of concurrency limit must be counted as errors,
// since this usually means the backend cannot keep up with the current load.
ui.backendErrors.Inc()
return
}
processRequest(w, r, ui)

View File

@@ -372,6 +372,7 @@ func main() {
if err != nil {
return cli.Exit(fmt.Errorf("cannot open exported block at path=%q err=%w", blockPath, err), 1)
}
defer f.Close()
var blocksCount atomic.Uint64
if err := stream.Parse(f, isBlockGzipped, func(_ *stream.Block) error {
blocksCount.Add(1)

View File

@@ -1,10 +1,11 @@
FROM node:18-alpine3.17
FROM node:20-alpine3.19
# Sets a custom location for the npm cache, preventing access errors in system directories
ENV NPM_CONFIG_CACHE=/build/.npm
RUN apk update && apk upgrade
RUN apk add --no-cache bash bash-doc bash-completion libtool autoconf automake nasm pkgconfig libpng gcc make g++ zlib-dev gawk
RUN apk update && \
apk upgrade && \
apk add --no-cache bash bash-doc bash-completion libtool autoconf automake nasm pkgconfig libpng gcc make g++ zlib-dev gawk && \
mkdir -p /app
RUN mkdir -p /app
WORKDIR /app

View File

@@ -14,5 +14,5 @@ COPY --from=build-web-stage /build/web-windows /app/web-windows
RUN adduser -S -D -u 1000 web && chown -R web /app
USER web
EXPOSE 8080
ENTRYPOINT ["/app/web"]

View File

@@ -1,3 +1,3 @@
## Predefined dashboards
See [this docs](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmui#predefined-dashboards)
See [this doc](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmui#predefined-dashboards)

View File

@@ -7,10 +7,11 @@ import "./style.scss";
interface LegendProps {
labels: LegendItemType[];
query: string[];
isAnomalyView?: boolean;
onChange: (item: LegendItemType, metaKey: boolean) => void;
}
const Legend: FC<LegendProps> = ({ labels, query, onChange }) => {
const Legend: FC<LegendProps> = ({ labels, query, isAnomalyView, onChange }) => {
const groups = useMemo(() => {
return Array.from(new Set(labels.map(l => l.group)));
}, [labels]);
@@ -39,6 +40,7 @@ const Legend: FC<LegendProps> = ({ labels, query, onChange }) => {
<LegendItem
key={legendItem.label}
legend={legendItem}
isAnomalyView={isAnomalyView}
onChange={onChange}
/>
)}

View File

@@ -11,9 +11,10 @@ interface LegendItemProps {
legend: LegendItemType;
onChange?: (item: LegendItemType, metaKey: boolean) => void;
isHeatmap?: boolean;
isAnomalyView?: boolean;
}
const LegendItem: FC<LegendItemProps> = ({ legend, onChange, isHeatmap }) => {
const LegendItem: FC<LegendItemProps> = ({ legend, onChange, isHeatmap, isAnomalyView }) => {
const copyToClipboard = useCopyToClipboard();
const freeFormFields = useMemo(() => {
@@ -47,7 +48,7 @@ const LegendItem: FC<LegendItemProps> = ({ legend, onChange, isHeatmap }) => {
})}
onClick={createHandlerClick(legend)}
>
{!isHeatmap && (
{!isAnomalyView && !isHeatmap && (
<div
className="vm-legend-item__marker"
style={{ backgroundColor: legend.color }}

View File

@@ -9,8 +9,8 @@ type Props = {
const titles: Partial<Record<ForecastType, string>> = {
[ForecastType.yhat]: "yhat",
[ForecastType.yhatLower]: "yhat_lower/_upper",
[ForecastType.yhatUpper]: "yhat_lower/_upper",
[ForecastType.yhatLower]: "yhat_upper - yhat_lower",
[ForecastType.yhatUpper]: "yhat_upper - yhat_lower",
[ForecastType.anomaly]: "anomalies",
[ForecastType.training]: "training data",
[ForecastType.actual]: "y"
@@ -42,9 +42,6 @@ const LegendAnomaly: FC<Props> = ({ series }) => {
}));
}, [series]);
const container = document.getElementById("legendAnomaly");
if (!container) return null;
return <>
<div className="vm-legend-anomaly">
{/* TODO: remove .filter() after the correct training data has been added */}

View File

@@ -40,7 +40,7 @@ export interface LineChartProps {
setPeriod: ({ from, to }: { from: Date, to: Date }) => void;
layoutSize: ElementSize;
height?: number;
anomalyView?: boolean;
isAnomalyView?: boolean;
spanGaps?: boolean;
}
@@ -54,7 +54,7 @@ const LineChart: FC<LineChartProps> = ({
setPeriod,
layoutSize,
height,
anomalyView,
isAnomalyView,
spanGaps = false
}) => {
const { isDarkTheme } = useAppState();
@@ -73,7 +73,7 @@ const LineChart: FC<LineChartProps> = ({
seriesFocus,
setCursor,
resetTooltips
} = useLineTooltip({ u: uPlotInst, metrics, series, unit, anomalyView });
} = useLineTooltip({ u: uPlotInst, metrics, series, unit, isAnomalyView });
const options: uPlotOptions = {
...getDefaultOptions({ width: layoutSize.width, height }),

View File

@@ -12,8 +12,11 @@ import useBoolean from "../../../hooks/useBoolean";
import useEventListener from "../../../hooks/useEventListener";
import Tooltip from "../../Main/Tooltip/Tooltip";
import { AUTOCOMPLETE_QUICK_KEY } from "../../Main/ShortcutKeys/constants/keyList";
import { QueryConfiguratorProps } from "../../../pages/CustomPanel/QueryConfigurator/QueryConfigurator";
const AdditionalSettingsControls: FC<{isMobile?: boolean}> = ({ isMobile }) => {
type Props = Pick<QueryConfiguratorProps, "hideButtons">;
const AdditionalSettingsControls: FC<Props & {isMobile?: boolean}> = ({ isMobile, hideButtons }) => {
const { autocomplete } = useQueryState();
const queryDispatch = useQueryDispatch();
@@ -54,31 +57,35 @@ const AdditionalSettingsControls: FC<{isMobile?: boolean}> = ({ isMobile }) => {
"vm-additional-settings_mobile": isMobile
})}
>
<Tooltip title={<>Quick tip: {AUTOCOMPLETE_QUICK_KEY}</>}>
<Switch
label={"Autocomplete"}
value={autocomplete}
onChange={onChangeAutocomplete}
fullWidth={isMobile}
/>
</Tooltip>
{!hideButtons?.autocomplete && (
<Tooltip title={<>Quick tip: {AUTOCOMPLETE_QUICK_KEY}</>}>
<Switch
label={"Autocomplete"}
value={autocomplete}
onChange={onChangeAutocomplete}
fullWidth={isMobile}
/>
</Tooltip>
)}
<Switch
label={"Disable cache"}
value={nocache}
onChange={onChangeCache}
fullWidth={isMobile}
/>
<Switch
label={"Trace query"}
value={isTracingEnabled}
onChange={onChangeQueryTracing}
fullWidth={isMobile}
/>
{!hideButtons?.traceQuery && (
<Switch
label={"Trace query"}
value={isTracingEnabled}
onChange={onChangeQueryTracing}
fullWidth={isMobile}
/>
)}
</div>
);
};
const AdditionalSettings: FC = () => {
const AdditionalSettings: FC<Props> = (props) => {
const { isMobile } = useDeviceDetect();
const targetRef = useRef<HTMLDivElement>(null);
@@ -106,13 +113,16 @@ const AdditionalSettings: FC = () => {
onClose={handleCloseList}
title={"Query settings"}
>
<AdditionalSettingsControls isMobile={isMobile}/>
<AdditionalSettingsControls
isMobile={isMobile}
{...props}
/>
</Popper>
</>
);
}
return <AdditionalSettingsControls/>;
return <AdditionalSettingsControls {...props}/>;
};
export default AdditionalSettings;

View File

@@ -25,6 +25,7 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
import useElementSize from "../../../hooks/useElementSize";
import { ChartTooltipProps } from "../../Chart/ChartTooltip/ChartTooltip";
import LegendAnomaly from "../../Chart/Line/LegendAnomaly/LegendAnomaly";
import { groupByMultipleKeys } from "../../../utils/array";
export interface GraphViewProps {
data?: MetricResult[];
@@ -40,7 +41,7 @@ export interface GraphViewProps {
fullWidth?: boolean;
height?: number;
isHistogram?: boolean;
anomalyView?: boolean;
isAnomalyView?: boolean;
spanGaps?: boolean;
}
@@ -58,7 +59,7 @@ const GraphView: FC<GraphViewProps> = ({
fullWidth = true,
height,
isHistogram,
anomalyView,
isAnomalyView,
spanGaps
}) => {
const { isMobile } = useDeviceDetect();
@@ -74,8 +75,8 @@ const GraphView: FC<GraphViewProps> = ({
const [legendValue, setLegendValue] = useState<ChartTooltipProps | null>(null);
const getSeriesItem = useMemo(() => {
return getSeriesItemContext(data, hideSeries, alias, anomalyView);
}, [data, hideSeries, alias, anomalyView]);
return getSeriesItemContext(data, hideSeries, alias, isAnomalyView);
}, [data, hideSeries, alias, isAnomalyView]);
const setLimitsYaxis = (values: { [key: string]: number[] }) => {
const limits = getLimitsYAxis(values, !isHistogram);
@@ -83,7 +84,7 @@ const GraphView: FC<GraphViewProps> = ({
};
const onChangeLegend = (legend: LegendItemType, metaKey: boolean) => {
setHideSeries(getHideSeries({ hideSeries, legend, metaKey, series }));
setHideSeries(getHideSeries({ hideSeries, legend, metaKey, series, isAnomalyView }));
};
const prepareHistogramData = (data: (number | null)[][]) => {
@@ -108,6 +109,20 @@ const GraphView: FC<GraphViewProps> = ({
return [null, [xs, ys, counts]];
};
const prepareAnomalyLegend = (legend: LegendItemType[]): LegendItemType[] => {
if (!isAnomalyView) return legend;
// For vmanomaly: Only select the first series per group (due to API specs) and clear __name__ in freeFormFields.
const grouped = groupByMultipleKeys(legend, ["group", "label"]);
return grouped.map((group) => {
const firstEl = group.values[0];
return {
...firstEl,
freeFormFields: { ...firstEl.freeFormFields, __name__: "" }
};
});
};
useEffect(() => {
const tempTimes: number[] = [];
const tempValues: { [key: string]: number[] } = {};
@@ -153,14 +168,18 @@ const GraphView: FC<GraphViewProps> = ({
const range = getMinMaxBuffer(getMinFromArray(resultAsNumber), getMaxFromArray(resultAsNumber));
const rangeStep = Math.abs(range[1] - range[0]);
return (avg > rangeStep * 1e10) && !anomalyView ? results.map(() => avg) : results;
return (avg > rangeStep * 1e10) && !isAnomalyView ? results.map(() => avg) : results;
});
timeDataSeries.unshift(timeSeries);
setLimitsYaxis(tempValues);
const result = isHistogram ? prepareHistogramData(timeDataSeries) : timeDataSeries;
setDataChart(result as uPlotData);
setSeries(tempSeries);
setLegend(tempLegend);
const legend = prepareAnomalyLegend(tempLegend);
setLegend(legend);
if (isAnomalyView) {
setHideSeries(legend.map(s => s.label || "").slice(1));
}
}, [data, timezone, isHistogram]);
useEffect(() => {
@@ -172,7 +191,7 @@ const GraphView: FC<GraphViewProps> = ({
tempLegend.push(getLegendItem(seriesItem, d.group));
});
setSeries(tempSeries);
setLegend(tempLegend);
setLegend(prepareAnomalyLegend(tempLegend));
}, [hideSeries]);
const [containerRef, containerSize] = useElementSize();
@@ -197,7 +216,7 @@ const GraphView: FC<GraphViewProps> = ({
setPeriod={setPeriod}
layoutSize={containerSize}
height={height}
anomalyView={anomalyView}
isAnomalyView={isAnomalyView}
spanGaps={spanGaps}
/>
)}
@@ -213,10 +232,12 @@ const GraphView: FC<GraphViewProps> = ({
onChangeLegend={setLegendValue}
/>
)}
{!isHistogram && !anomalyView && showLegend && (
{isAnomalyView && showLegend && (<LegendAnomaly series={series as SeriesItem[]}/>)}
{!isHistogram && showLegend && (
<Legend
labels={legend}
query={query}
isAnomalyView={isAnomalyView}
onChange={onChangeLegend}
/>
)}
@@ -228,11 +249,6 @@ const GraphView: FC<GraphViewProps> = ({
legendValue={legendValue}
/>
)}
{anomalyView && showLegend && (
<LegendAnomaly
series={series as SeriesItem[]}
/>
)}
</div>
);
};

View File

@@ -62,10 +62,6 @@ export const anomalyNavigation: NavigationItem[] = [
{
label: routerOptions[router.anomaly].title,
value: router.home,
},
{
label: routerOptions[router.home].title,
value: router.query,
}
];

View File

@@ -14,10 +14,10 @@ interface LineTooltipHook {
metrics: MetricResult[];
series: uPlotSeries[];
unit?: string;
anomalyView?: boolean;
isAnomalyView?: boolean;
}
const useLineTooltip = ({ u, metrics, series, unit, anomalyView }: LineTooltipHook) => {
const useLineTooltip = ({ u, metrics, series, unit, isAnomalyView }: LineTooltipHook) => {
const [showTooltip, setShowTooltip] = useState(false);
const [tooltipIdx, setTooltipIdx] = useState({ seriesIdx: -1, dataIdx: -1 });
const [stickyTooltips, setStickyToolTips] = useState<ChartTooltipProps[]>([]);
@@ -61,14 +61,14 @@ const useLineTooltip = ({ u, metrics, series, unit, anomalyView }: LineTooltipHo
point,
u: u,
id: `${seriesIdx}_${dataIdx}`,
title: groups.size > 1 && !anomalyView ? `Query ${group}` : "",
title: groups.size > 1 && !isAnomalyView ? `Query ${group}` : "",
dates: [date ? dayjs(date * 1000).tz().format(DATE_FULL_TIMEZONE_FORMAT) : "-"],
value: formatPrettyNumber(value, min, max),
info: getMetricName(metricItem),
statsFormatted: seriesItem?.statsFormatted,
marker: `${seriesItem?.stroke}`,
};
}, [u, tooltipIdx, metrics, series, unit, anomalyView]);
}, [u, tooltipIdx, metrics, series, unit, isAnomalyView]);
const handleClick = useCallback(() => {
if (!showTooltip) return;

View File

@@ -12,7 +12,8 @@ import { useTimeState } from "../state/time/TimeStateContext";
import { useCustomPanelState } from "../state/customPanel/CustomPanelStateContext";
import { isHistogramData } from "../utils/metric";
import { useGraphState } from "../state/graph/GraphStateContext";
import { getStepFromDuration } from "../utils/time";
import { getSecondsFromDuration, getStepFromDuration } from "../utils/time";
import { AppType } from "../types/appType";
interface FetchQueryParams {
predefinedQuery?: string[]
@@ -47,13 +48,15 @@ interface FetchDataParams {
hideQuery?: number[]
}
const isAnomalyUI = AppType.anomaly === process.env.REACT_APP_TYPE;
export const useFetchQuery = ({
predefinedQuery,
visible,
display,
customStep,
hideQuery,
showAllSeries
showAllSeries,
}: FetchQueryParams): FetchQueryReturn => {
const { query } = useQueryState();
const { period } = useTimeState();
@@ -124,7 +127,7 @@ export const useFetchQuery = ({
tempTraces.push(trace);
}
isHistogramResult = isDisplayChart && isHistogramData(resp.data.result);
isHistogramResult = !isAnomalyUI && isDisplayChart && isHistogramData(resp.data.result);
seriesLimit = isHistogramResult ? Infinity : defaultLimit;
const freeTempSize = seriesLimit - tempData.length;
resp.data.result.slice(0, freeTempSize).forEach((d: MetricBase) => {
@@ -172,7 +175,7 @@ export const useFetchQuery = ({
setQueryErrors(expr.map(() => ErrorTypes.validQuery));
} else if (isValidHttpUrl(serverUrl)) {
const updatedPeriod = { ...period };
updatedPeriod.step = customStep;
updatedPeriod.step = isAnomalyUI ? `${getSecondsFromDuration(customStep)*1000}ms` : customStep;
return expr.map(q => displayChart
? getQueryRangeUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled)
: getQueryUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled));

View File

@@ -14,10 +14,10 @@ type Props = {
isHistogram: boolean;
graphData: MetricResult[];
controlsRef: React.RefObject<HTMLDivElement>;
anomalyView?: boolean;
isAnomalyView?: boolean;
}
const GraphTab: FC<Props> = ({ isHistogram, graphData, controlsRef, anomalyView }) => {
const GraphTab: FC<Props> = ({ isHistogram, graphData, controlsRef, isAnomalyView }) => {
const { isMobile } = useDeviceDetect();
const { customStep, yaxis, spanGaps } = useGraphState();
@@ -68,7 +68,7 @@ const GraphTab: FC<Props> = ({ isHistogram, graphData, controlsRef, anomalyView
setPeriod={setPeriod}
height={isMobile ? window.innerHeight * 0.5 : 500}
isHistogram={isHistogram}
anomalyView={anomalyView}
isAnomalyView={isAnomalyView}
spanGaps={spanGaps}
/>
</>

View File

@@ -30,8 +30,14 @@ export interface QueryConfiguratorProps {
setQueryErrors: StateUpdater<string[]>;
setHideError: StateUpdater<boolean>;
stats: QueryStats[];
onHideQuery: (queries: number[]) => void
onRunQuery: () => void
onHideQuery?: (queries: number[]) => void
onRunQuery: () => void;
hideButtons?: {
addQuery?: boolean;
prettify?: boolean;
autocomplete?: boolean;
traceQuery?: boolean;
}
}
const QueryConfigurator: FC<QueryConfiguratorProps> = ({
@@ -40,7 +46,8 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
setHideError,
stats,
onHideQuery,
onRunQuery
onRunQuery,
hideButtons
}) => {
const { isMobile } = useDeviceDetect();
@@ -159,7 +166,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
}, [stateQuery]);
useEffect(() => {
onHideQuery(hideQuery);
onHideQuery && onHideQuery(hideQuery);
}, [hideQuery]);
useEffect(() => {
@@ -188,40 +195,43 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
>
<QueryEditor
value={stateQuery[i]}
autocomplete={autocomplete || autocompleteQuick}
autocomplete={!hideButtons?.autocomplete && (autocomplete || autocompleteQuick)}
error={queryErrors[i]}
stats={stats[i]}
onArrowUp={createHandlerArrow(-1, i)}
onArrowDown={createHandlerArrow(1, i)}
onEnter={handleRunQuery}
onChange={createHandlerChangeQuery(i)}
label={`Query ${i + 1}`}
label={`Query ${stateQuery.length > 1 ? i + 1 : ""}`}
disabled={hideQuery.includes(i)}
/>
<Tooltip title={hideQuery.includes(i) ? "Enable query" : "Disable query"}>
<div className="vm-query-configurator-list-row__button">
<Button
variant={"text"}
color={"gray"}
startIcon={hideQuery.includes(i) ? <VisibilityOffIcon/> : <VisibilityIcon/>}
onClick={createHandlerHideQuery(i)}
ariaLabel="visibility query"
/>
</div>
</Tooltip>
{onHideQuery && (
<Tooltip title={hideQuery.includes(i) ? "Enable query" : "Disable query"}>
<div className="vm-query-configurator-list-row__button">
<Button
variant={"text"}
color={"gray"}
startIcon={hideQuery.includes(i) ? <VisibilityOffIcon/> : <VisibilityIcon/>}
onClick={createHandlerHideQuery(i)}
ariaLabel="visibility query"
/>
</div>
</Tooltip>
)}
<Tooltip title={"Prettify query"}>
<div className="vm-query-configurator-list-row__button">
<Button
variant={"text"}
color={"gray"}
startIcon={<Prettify/>}
onClick={async () => await handlePrettifyQuery(i)}
className="prettify"
ariaLabel="prettify the query"
/>
</div>
</Tooltip>
{!hideButtons?.prettify && (
<Tooltip title={"Prettify query"}>
<div className="vm-query-configurator-list-row__button">
<Button
variant={"text"}
color={"gray"}
startIcon={<Prettify/>}
onClick={async () => await handlePrettifyQuery(i)}
className="prettify"
ariaLabel="prettify the query"
/>
</div>
</Tooltip>)}
{stateQuery.length > 1 && (
<Tooltip title="Remove Query">
@@ -240,10 +250,10 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
))}
</div>
<div className="vm-query-configurator-settings">
<AdditionalSettings/>
<AdditionalSettings hideButtons={hideButtons}/>
<div className="vm-query-configurator-settings__buttons">
<QueryHistory handleSelectQuery={handleSelectHistory}/>
{stateQuery.length < MAX_QUERY_FIELDS && (
{!hideButtons?.addQuery && stateQuery.length < MAX_QUERY_FIELDS && (
<Button
variant="outlined"
onClick={handleAddQuery}

View File

@@ -33,7 +33,7 @@
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
justify-content: space-between;
font-size: $font-size-small;
margin: -$padding-medium 0-$padding-medium $padding-medium;
padding: 0 $padding-medium;

View File

@@ -1,60 +1,63 @@
import React, { FC, useMemo, useRef } from "preact/compat";
import React, { FC, useMemo, useRef, useState } from "preact/compat";
import classNames from "classnames";
import useDeviceDetect from "../../hooks/useDeviceDetect";
import useEventListener from "../../hooks/useEventListener";
import { ForecastType } from "../../types";
import { useSetQueryParams } from "../CustomPanel/hooks/useSetQueryParams";
import QueryConfigurator from "../CustomPanel/QueryConfigurator/QueryConfigurator";
import "../CustomPanel/style.scss";
import ExploreAnomalyHeader from "./ExploreAnomalyHeader/ExploreAnomalyHeader";
import Alert from "../../components/Main/Alert/Alert";
import { extractFields, isForecast } from "../../utils/uplot";
import { useQueryState } from "../../state/query/QueryStateContext";
import { useFetchQuery } from "../../hooks/useFetchQuery";
import Spinner from "../../components/Main/Spinner/Spinner";
import GraphTab from "../CustomPanel/CustomPanelTabs/GraphTab";
import { useGraphState } from "../../state/graph/GraphStateContext";
import Spinner from "../../components/Main/Spinner/Spinner";
import Alert from "../../components/Main/Alert/Alert";
import WarningLimitSeries from "../CustomPanel/WarningLimitSeries/WarningLimitSeries";
import GraphTab from "../CustomPanel/CustomPanelTabs/GraphTab";
import { extractFields, isForecast } from "../../utils/uplot";
import { MetricResult } from "../../api/types";
import { promValueToNumber } from "../../utils/metric";
import { ForecastType } from "../../types";
import { useFetchAnomalySeries } from "./hooks/useFetchAnomalySeries";
import { useQueryDispatch } from "../../state/query/QueryStateContext";
import { useTimeDispatch } from "../../state/time/TimeStateContext";
const anomalySeries = [
ForecastType.yhat,
ForecastType.yhatUpper,
ForecastType.yhatLower,
ForecastType.anomalyScore
];
// Hardcoded to 1.0 for now; consider adding a UI slider for threshold adjustment in the future.
const ANOMALY_SCORE_THRESHOLD = 1;
const ExploreAnomaly: FC = () => {
useSetQueryParams();
const { isMobile } = useDeviceDetect();
const queryDispatch = useQueryDispatch();
const timeDispatch = useTimeDispatch();
const { series, error: errorSeries, isLoading: isAnomalySeriesLoading } = useFetchAnomalySeries();
const queries = useMemo(() => series ? Object.keys(series) : [], [series]);
const controlsRef = useRef<HTMLDivElement>(null);
const { query } = useQueryState();
const { customStep } = useGraphState();
const { graphData, error, queryErrors, isHistogram, isLoading: isGraphDataLoading } = useFetchQuery({
const controlsRef = useRef<HTMLDivElement>(null);
const [hideQuery] = useState<number[]>([]);
const [hideError, setHideError] = useState(!query[0]);
const [showAllSeries, setShowAllSeries] = useState(false);
const {
isLoading,
graphData,
error,
queryErrors,
setQueryErrors,
queryStats,
warning,
} = useFetchQuery({
visible: true,
customStep,
showAllSeries: true,
hideQuery,
showAllSeries
});
const data = useMemo(() => {
if (!graphData) return;
if (!graphData) return [];
const detectedData = graphData.map(d => ({ ...isForecast(d.metric), ...d }));
const realData = detectedData.filter(d => d.value === null);
const anomalyScoreData = detectedData.filter(d => d.isAnomalyScore);
const realData = detectedData.filter(d => d.value === ForecastType.actual);
const anomalyScoreData = detectedData.filter(d => d.value === ForecastType.anomaly);
const anomalyData: MetricResult[] = realData.map((d) => {
const id = extractFields(d.metric);
const anomalyScoreDataByLabels = anomalyScoreData.find(du => extractFields(du.metric) === id);
return {
group: queries.length + 1,
group: 1,
metric: { ...d.metric, __name__: ForecastType.anomaly },
values: d.values.filter(([t]) => {
if (!anomalyScoreDataByLabels) return false;
@@ -63,23 +66,14 @@ const ExploreAnomaly: FC = () => {
})
};
});
return graphData.filter(d => d.group !== anomalyScoreData[0]?.group).concat(anomalyData);
const filterData = detectedData.filter(d => (d.value !== ForecastType.anomaly) && d.value) as MetricResult[];
return filterData.concat(anomalyData);
}, [graphData]);
const onChangeFilter = (expr: Record<string, string>) => {
const { __name__ = "", ...labelValue } = expr;
let prefix = __name__.replace(/y|_y/, "");
if (prefix) prefix += "_";
const metrics = [__name__, ...anomalySeries];
const filters = Object.entries(labelValue).map(([key, value]) => `${key}="${value}"`).join(",");
const queries = metrics.map((m, i) => `${i ? prefix : ""}${m}{${filters}}`);
queryDispatch({ type: "SET_QUERY", payload: queries });
timeDispatch({ type: "RUN_QUERY" });
const handleRunQuery = () => {
setHideError(false);
};
const handleChangePopstate = () => window.location.reload();
useEventListener("popstate", handleChangePopstate);
return (
<div
className={classNames({
@@ -87,14 +81,23 @@ const ExploreAnomaly: FC = () => {
"vm-custom-panel_mobile": isMobile,
})}
>
<ExploreAnomalyHeader
queries={queries}
series={series}
onChange={onChangeFilter}
<QueryConfigurator
queryErrors={!hideError ? queryErrors : []}
setQueryErrors={setQueryErrors}
setHideError={setHideError}
stats={queryStats}
onRunQuery={handleRunQuery}
hideButtons={{ addQuery: true, prettify: true, autocomplete: true, traceQuery: true }}
/>
{(isGraphDataLoading || isAnomalySeriesLoading) && <Spinner />}
{(error || errorSeries) && <Alert variant="error">{error || errorSeries}</Alert>}
{!error && !errorSeries && queryErrors?.[0] && <Alert variant="error">{queryErrors[0]}</Alert>}
{isLoading && <Spinner/>}
{(!hideError && error) && <Alert variant="error">{error}</Alert>}
{warning && (
<WarningLimitSeries
warning={warning}
query={query}
onChange={setShowAllSeries}
/>
)}
<div
className={classNames({
"vm-custom-panel-body": true,
@@ -112,9 +115,9 @@ const ExploreAnomaly: FC = () => {
{data && (
<GraphTab
graphData={data}
isHistogram={isHistogram}
isHistogram={false}
controlsRef={controlsRef}
anomalyView={true}
isAnomalyView={true}
/>
)}
</div>

View File

@@ -1,112 +0,0 @@
import React, { FC, useMemo, useState } from "preact/compat";
import classNames from "classnames";
import useDeviceDetect from "../../../hooks/useDeviceDetect";
import Select from "../../../components/Main/Select/Select";
import "./style.scss";
import usePrevious from "../../../hooks/usePrevious";
import { useEffect } from "react";
import { arrayEquals } from "../../../utils/array";
import { getQueryStringValue } from "../../../utils/query-string";
import { useSetQueryParams } from "../hooks/useSetQueryParams";
type Props = {
queries: string[];
series?: Record<string, {[p: string]: string}[]>
onChange: (expr: Record<string, string>) => void;
}
const ExploreAnomalyHeader: FC<Props> = ({ queries, series, onChange }) => {
const { isMobile } = useDeviceDetect();
const [alias, setAlias] = useState(queries[0]);
const [selectedValues, setSelectedValues] = useState<Record<string, string>>({});
useSetQueryParams({ alias: alias, ...selectedValues });
const uniqueKeysWithValues = useMemo(() => {
if (!series) return {};
return series[alias]?.reduce((accumulator, currentSeries) => {
const metric = Object.entries(currentSeries);
if (!metric.length) return accumulator;
const excludeMetrics = ["__name__", "for"];
for (const [key, value] of metric) {
if (excludeMetrics.includes(key) || accumulator[key]?.includes(value)) continue;
if (!accumulator[key]) {
accumulator[key] = [];
}
accumulator[key].push(value);
}
return accumulator;
}, {} as Record<string, string[]>) || {};
}, [alias, series]);
const prevUniqueKeysWithValues = usePrevious(uniqueKeysWithValues);
const createHandlerChangeSelect = (key: string) => (value: string) => {
setSelectedValues((prev) => ({ ...prev, [key]: value }));
};
useEffect(() => {
const nextValues = Object.values(uniqueKeysWithValues).flat();
const prevValues = Object.values(prevUniqueKeysWithValues || {}).flat();
if (arrayEquals(prevValues, nextValues)) return;
const newSelectedValues: Record<string, string> = {};
Object.keys(uniqueKeysWithValues).forEach((key) => {
const value = getQueryStringValue(key, "") as string;
newSelectedValues[key] = value || uniqueKeysWithValues[key]?.[0];
});
setSelectedValues(newSelectedValues);
}, [uniqueKeysWithValues, prevUniqueKeysWithValues]);
useEffect(() => {
if (!alias || !Object.keys(selectedValues).length) return;
const __name__ = series?.[alias]?.[0]?.__name__ || "";
onChange({ ...selectedValues, for: alias, __name__ });
}, [selectedValues, alias]);
useEffect(() => {
setAlias(getQueryStringValue("alias", queries[0]) as string);
}, [series]);
return (
<div
id="legendAnomaly"
className={classNames({
"vm-explore-anomaly-header": true,
"vm-explore-anomaly-header_mobile": isMobile,
"vm-block": true,
"vm-block_mobile": isMobile,
})}
>
<div className="vm-explore-anomaly-header-main">
<div className="vm-explore-anomaly-header__select">
<Select
value={alias}
list={queries}
label="Query"
placeholder="Please select query"
onChange={setAlias}
searchable
/>
</div>
</div>
{Object.entries(uniqueKeysWithValues).map(([key, values]) => (
<div
className="vm-explore-anomaly-header__values"
key={key}
>
<Select
value={selectedValues[key] || ""}
list={values}
label={key}
placeholder={`Please select ${key}`}
onChange={createHandlerChangeSelect(key)}
searchable={values.length > 2}
disabled={values.length === 1}
/>
</div>
))}
</div>
);
};
export default ExploreAnomalyHeader;

View File

@@ -1,37 +0,0 @@
@use "src/styles/variables" as *;
.vm-explore-anomaly-header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
gap: $padding-global calc($padding-small + 10px);
max-width: calc(100vw - var(--scrollbar-width));
&_mobile {
flex-direction: column;
align-items: stretch;
}
&-main {
display: grid;
gap: $padding-large;
align-items: center;
justify-items: center;
flex-grow: 1;
width: 100%;
&__config {
text-transform: lowercase;
}
}
&__select {
flex-grow: 1;
min-width: 100%;
}
&__values {
flex-grow: 1;
}
}

View File

@@ -1,75 +0,0 @@
import { useMemo, useState } from "preact/compat";
import { useAppState } from "../../../state/common/StateContext";
import { ErrorTypes } from "../../../types";
import { useEffect } from "react";
import { MetricBase } from "../../../api/types";
import { useTimeState } from "../../../state/time/TimeStateContext";
import dayjs from "dayjs";
// TODO: Change the method of retrieving aliases from the configuration after the API has been added
const seriesQuery = `{
for!="",
__name__!~".*yhat.*|.*trend.*|.*anomaly_score.*|.*daily.*|.*additive_terms.*|.*multiplicative_terms.*|.*weekly.*"
}`;
export const useFetchAnomalySeries = () => {
const { serverUrl } = useAppState();
const { period: { start, end } } = useTimeState();
const [series, setSeries] = useState<Record<string, MetricBase["metric"][]>>();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<ErrorTypes | string>();
// TODO add cached metrics by date
const fetchUrl = useMemo(() => {
const startDay = dayjs(start * 1000).startOf("day").valueOf() / 1000;
const endDay = dayjs(end * 1000).endOf("day").valueOf() / 1000;
const params = new URLSearchParams({
"match[]": seriesQuery,
start: `${startDay}`,
end: `${endDay}`
});
return `${serverUrl}/api/v1/series?${params}`;
}, [serverUrl, start, end]);
useEffect(() => {
const fetchSeries = async () => {
setError("");
setIsLoading(true);
try {
const response = await fetch(fetchUrl);
const resp = await response.json();
const data = (resp?.data || []) as MetricBase["metric"][];
const groupedByFor = data.reduce<{ [key: string]: MetricBase["metric"][] }>((acc, item) => {
const forKey = item["for"];
if (!acc[forKey]) acc[forKey] = [];
acc[forKey].push(item);
return acc;
}, {});
setSeries(groupedByFor);
if (!response.ok) {
const errorType = resp.errorType ? `${resp.errorType}\r\n` : "";
setError(`${errorType}${resp?.error || resp?.message}`);
}
} catch (e) {
if (e instanceof Error && e.name !== "AbortError") {
const message = e.name === "SyntaxError" ? ErrorTypes.unknownType : `${e.name}: ${e.message}`;
setError(`${message}`);
}
} finally {
setIsLoading(false);
}
};
fetchSeries();
}, [fetchUrl]);
return {
error,
series,
isLoading,
};
};

View File

@@ -1,31 +0,0 @@
import { useEffect } from "react";
import { compactObject } from "../../../utils/object";
import { useTimeState } from "../../../state/time/TimeStateContext";
import { useGraphState } from "../../../state/graph/GraphStateContext";
import useSearchParamsFromObject from "../../../hooks/useSearchParamsFromObject";
interface stateParams extends Record<string, string> {
alias: string;
}
export const useSetQueryParams = ({ alias, ...args }: stateParams) => {
const { duration, relativeTime, period: { date } } = useTimeState();
const { customStep } = useGraphState();
const { setSearchParamsFromKeys } = useSearchParamsFromObject();
const setSearchParamsFromState = () => {
const params = compactObject({
["g0.range_input"]: duration,
["g0.end_input"]: date,
["g0.step_input"]: customStep,
["g0.relative_time"]: relativeTime,
alias,
...args,
});
setSearchParamsFromKeys(params);
};
useEffect(setSearchParamsFromState, [duration, relativeTime, date, customStep, alias, args]);
useEffect(setSearchParamsFromState, []);
};

View File

@@ -29,7 +29,8 @@ export interface HideSeriesArgs {
hideSeries: string[],
legend: LegendItemType,
metaKey: boolean,
series: Series[]
series: Series[],
isAnomalyView?: boolean,
}
export type MinMax = { min: number, max: number }

View File

@@ -8,9 +8,16 @@ export const getDefaultServer = (tenantId?: string): string => {
const { serverURL } = getAppModeParams();
const storageURL = getFromStorage("SERVER_URL") as string;
const logsURL = window.location.href.replace(/\/(select\/)?(vmui)\/.*/, "");
const anomalyURL = window.location.href.replace(/(?:graph|vmui)\/.*/, "");
const defaultURL = window.location.href.replace(/\/(?:prometheus\/)?(?:graph|vmui)\/.*/, "/prometheus");
const url = serverURL || storageURL || defaultURL;
if (REACT_APP_TYPE === AppType.logs) return logsURL;
if (tenantId) return replaceTenantId(url, tenantId);
return url;
switch (REACT_APP_TYPE) {
case AppType.logs:
return logsURL;
case AppType.anomaly:
return serverURL || storageURL || anomalyURL;
default:
return tenantId ? replaceTenantId(url, tenantId) : url;
}
};

View File

@@ -66,7 +66,7 @@ export const isSupportedDuration = (str: string): Partial<Record<UnitTypeShort,
export const getSecondsFromDuration = (dur: string) => {
const shortSupportedDur = supportedDurations.map(d => d.short).join("|");
const regexp = new RegExp(`\\d+[${shortSupportedDur}]+`, "g");
const regexp = new RegExp(`\\d+(\\.\\d+)?[${shortSupportedDur}]+`, "g");
const durItems = dur.match(regexp) || [];
const durObject = durItems.reduce((prev, curr) => {

View File

@@ -14,25 +14,26 @@ export const extractFields = (metric: MetricBase["metric"]): string => {
.map(([key, value]) => `${key}: ${value}`).join(",");
};
export const isForecast = (metric: MetricBase["metric"]) => {
type ForecastMetricInfo = {
value: ForecastType | null;
group: string;
}
export const isForecast = (metric: MetricBase["metric"]): ForecastMetricInfo => {
const metricName = metric?.__name__ || "";
const forecastRegex = new RegExp(`(${Object.values(ForecastType).join("|")})$`);
const match = metricName.match(forecastRegex);
const value = match && match[0] as ForecastType;
const isY = /(?:^|[^a-zA-Z0-9_])y(?:$|[^a-zA-Z0-9_])/.test(metricName);
return {
value,
isUpper: value === ForecastType.yhatUpper,
isLower: value === ForecastType.yhatLower,
isYhat: value === ForecastType.yhat,
isAnomaly: value === ForecastType.anomaly,
isAnomalyScore: value === ForecastType.anomalyScore,
value: isY ? ForecastType.actual : value,
group: extractFields(metric)
};
};
export const getSeriesItemContext = (data: MetricResult[], hideSeries: string[], alias: string[], isAnomaly?: boolean) => {
export const getSeriesItemContext = (data: MetricResult[], hideSeries: string[], alias: string[], isAnomalyUI?: boolean) => {
const colorState: {[key: string]: string} = {};
const maxColors = isAnomaly ? 0 : Math.min(data.length, baseContrastColors.length);
const maxColors = isAnomalyUI ? 0 : Math.min(data.length, baseContrastColors.length);
for (let i = 0; i < maxColors; i++) {
const label = getNameForMetric(data[i], alias[data[i].group - 1]);
@@ -40,77 +41,45 @@ export const getSeriesItemContext = (data: MetricResult[], hideSeries: string[],
}
return (d: MetricResult, i: number): SeriesItem => {
const forecast = isForecast(data[i].metric);
const label = isAnomaly ? forecast.group : getNameForMetric(d, alias[d.group - 1]);
const values = d.values.map(v => promValueToNumber(v[1]));
const { min, max, median, last } = {
min: getMinFromArray(values),
max: getMaxFromArray(values),
median: getMedianFromArray(values),
last: getLastFromArray(values),
};
let dash: number[] = [];
if (forecast.isLower || forecast.isUpper) {
dash = [10, 5];
} else if (forecast.isYhat) {
dash = [10, 2];
}
let width = 1.4;
if (forecast.isUpper || forecast.isLower) {
width = 0.7;
} else if (forecast.isYhat) {
width = 1;
} else if (forecast.isAnomaly) {
width = 0;
}
let points: uPlotSeries.Points = { size: 4.2, width: 1.4 };
if (forecast.isAnomaly) {
points = { size: 8, width: 4, space: 0 };
}
let stroke: uPlotSeries.Stroke = colorState[label] || getColorFromString(label);
if (isAnomaly && forecast.isAnomaly) {
stroke = anomalyColors[ForecastType.anomaly];
} else if (isAnomaly && !forecast.isAnomaly && !forecast.value) {
// TODO add stroke for training data
// const hzGrad: [number, string][] = [
// [time, anomalyColors[ForecastType.actual]],
// [time, anomalyColors[ForecastType.training]],
// [time, anomalyColors[ForecastType.actual]],
// ];
// stroke = scaleGradient("x", 0, hzGrad, true);
stroke = anomalyColors[ForecastType.actual];
} else if (forecast.value) {
stroke = forecast.value ? anomalyColors[forecast.value] : stroke;
}
const metricInfo = isAnomalyUI ? isForecast(data[i].metric) : null;
const label = isAnomalyUI ? metricInfo?.group || "" : getNameForMetric(d, alias[d.group - 1]);
return {
label,
dash,
width,
stroke,
points,
dash: getDashSeries(metricInfo),
width: getWidthSeries(metricInfo),
stroke: getStrokeSeries({ metricInfo, label, isAnomalyUI, colorState }),
points: getPointsSeries(metricInfo),
spanGaps: false,
forecast: forecast.value,
forecastGroup: forecast.group,
forecast: metricInfo?.value,
forecastGroup: metricInfo?.group,
freeFormFields: d.metric,
show: !includesHideSeries(label, hideSeries),
scale: "1",
statsFormatted: {
min: formatPrettyNumber(min, min, max),
max: formatPrettyNumber(max, min, max),
median: formatPrettyNumber(median, min, max),
last: formatPrettyNumber(last, min, max),
},
median: median,
...getSeriesStatistics(d),
};
};
};
const getSeriesStatistics = (d: MetricResult) => {
const values = d.values.map(v => promValueToNumber(v[1]));
const { min, max, median, last } = {
min: getMinFromArray(values),
max: getMaxFromArray(values),
median: getMedianFromArray(values),
last: getLastFromArray(values),
};
return {
median,
statsFormatted: {
min: formatPrettyNumber(min, min, max),
max: formatPrettyNumber(max, min, max),
median: formatPrettyNumber(median, min, max),
last: formatPrettyNumber(last, min, max),
},
};
};
export const getLegendItem = (s: SeriesItem, group: number): LegendItemType => ({
group,
label: s.label || "",
@@ -121,10 +90,16 @@ export const getLegendItem = (s: SeriesItem, group: number): LegendItemType => (
median: s.median,
});
export const getHideSeries = ({ hideSeries, legend, metaKey, series }: HideSeriesArgs): string[] => {
export const getHideSeries = ({ hideSeries, legend, metaKey, series, isAnomalyView }: HideSeriesArgs): string[] => {
const { label } = legend;
const include = includesHideSeries(label, hideSeries);
const labels = series.map(s => s.label || "");
// if anomalyView is true, always return all series except the one specified by `label`
if (isAnomalyView) {
return labels.filter(l => l !== label);
}
if (metaKey) {
return include ? hideSeries.filter(l => l !== label) : [...hideSeries, label];
} else if (hideSeries.length) {
@@ -172,3 +147,71 @@ export const addSeries = (u: uPlot, series: uPlotSeries[], spanGaps = false) =>
u.addSeries(s);
});
};
// Helpers
const getDashSeries = (metricInfo: ForecastMetricInfo | null): number[] => {
const isLower = metricInfo?.value === ForecastType.yhatLower;
const isUpper = metricInfo?.value === ForecastType.yhatUpper;
const isYhat = metricInfo?.value === ForecastType.yhat;
if (isLower || isUpper) {
return [10, 5];
} else if (isYhat) {
return [10, 2];
}
return [];
};
const getWidthSeries = (metricInfo: ForecastMetricInfo | null): number => {
const isLower = metricInfo?.value === ForecastType.yhatLower;
const isUpper = metricInfo?.value === ForecastType.yhatUpper;
const isYhat = metricInfo?.value === ForecastType.yhat;
const isAnomalyMetric = metricInfo?.value === ForecastType.anomaly;
if (isUpper || isLower) {
return 0.7;
} else if (isYhat) {
return 1;
} else if (isAnomalyMetric) {
return 0;
}
return 1.4;
};
const getPointsSeries = (metricInfo: ForecastMetricInfo | null): uPlotSeries.Points => {
const isAnomalyMetric = metricInfo?.value === ForecastType.anomaly;
if (isAnomalyMetric) {
return { size: 8, width: 4, space: 0 };
}
return { size: 4.2, width: 1.4 };
};
type GetStrokeSeriesArgs = {
metricInfo: ForecastMetricInfo | null,
label: string,
colorState: {[p: string]: string},
isAnomalyUI?: boolean
}
const getStrokeSeries = ({ metricInfo, label, isAnomalyUI, colorState }: GetStrokeSeriesArgs): uPlotSeries.Stroke => {
const stroke: uPlotSeries.Stroke = colorState[label] || getColorFromString(label);
const isAnomalyMetric = metricInfo?.value === ForecastType.anomaly;
if (isAnomalyUI && isAnomalyMetric) {
return anomalyColors[ForecastType.anomaly];
} else if (isAnomalyUI && !isAnomalyMetric && !metricInfo?.value) {
// TODO add stroke for training data
// const hzGrad: [number, string][] = [
// [time, anomalyColors[ForecastType.actual]],
// [time, anomalyColors[ForecastType.training]],
// [time, anomalyColors[ForecastType.actual]],
// ];
// stroke = scaleGradient("x", 0, hzGrad, true);
return anomalyColors[ForecastType.actual];
} else if (metricInfo?.value) {
return metricInfo?.value ? anomalyColors[metricInfo?.value] : stroke;
}
return colorState[label] || getColorFromString(label);
};

View File

@@ -310,7 +310,7 @@
"refId": "A"
}
],
"title": "Comprasion ratio",
"title": "Compression ratio",
"type": "stat"
},
{
@@ -2700,4 +2700,4 @@
"uid": "OqPIZTX4z",
"version": 1,
"weekStart": ""
}
}

View File

@@ -5,7 +5,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.100.0
image: victoriametrics/vmagent:v1.100.1
depends_on:
- "vminsert"
ports:
@@ -39,7 +39,7 @@ services:
# where N is number of vmstorages (2 in this case).
vmstorage-1:
container_name: vmstorage-1
image: victoriametrics/vmstorage:v1.100.0-cluster
image: victoriametrics/vmstorage:v1.100.1-cluster
ports:
- 8482
- 8400
@@ -51,7 +51,7 @@ services:
restart: always
vmstorage-2:
container_name: vmstorage-2
image: victoriametrics/vmstorage:v1.100.0-cluster
image: victoriametrics/vmstorage:v1.100.1-cluster
ports:
- 8482
- 8400
@@ -66,7 +66,7 @@ services:
# pre-process them and distributes across configured vmstorage shards.
vminsert:
container_name: vminsert
image: victoriametrics/vminsert:v1.100.0-cluster
image: victoriametrics/vminsert:v1.100.1-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -81,7 +81,7 @@ services:
# vmselect collects results from configured `--storageNode` shards.
vmselect-1:
container_name: vmselect-1
image: victoriametrics/vmselect:v1.100.0-cluster
image: victoriametrics/vmselect:v1.100.1-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -94,7 +94,7 @@ services:
restart: always
vmselect-2:
container_name: vmselect-2
image: victoriametrics/vmselect:v1.100.0-cluster
image: victoriametrics/vmselect:v1.100.1-cluster
depends_on:
- "vmstorage-1"
- "vmstorage-2"
@@ -112,7 +112,7 @@ services:
# It can be used as an authentication proxy.
vmauth:
container_name: vmauth
image: victoriametrics/vmauth:v1.100.0
image: victoriametrics/vmauth:v1.100.1
depends_on:
- "vmselect-1"
- "vmselect-2"
@@ -127,7 +127,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.100.0
image: victoriametrics/vmalert:v1.100.1
depends_on:
- "vmauth"
ports:

View File

@@ -58,7 +58,7 @@ services:
# scraping, storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- 8428:8428
volumes:

View File

@@ -5,7 +5,7 @@ services:
# And forward them to --remoteWrite.url
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.100.0
image: victoriametrics/vmagent:v1.100.1
depends_on:
- "victoriametrics"
ports:
@@ -23,7 +23,7 @@ services:
# storing metrics and serve read requests.
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- 8428:8428
- 8089:8089
@@ -66,7 +66,7 @@ services:
# vmalert executes alerting and recording rules
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.100.0
image: victoriametrics/vmalert:v1.100.1
depends_on:
- "victoriametrics"
- "alertmanager"

View File

@@ -19,19 +19,14 @@
'''
[sinks.vlogs]
type = "elasticsearch"
type = "http"
inputs = [ "msg_parser" ]
endpoints = [ "http://victorialogs:9428/insert/elasticsearch/" ]
mode = "bulk"
api_version = "v8"
uri = "http://victorialogs:9428/insert/jsonline?_stream_fields=source_type,host,container_name&_msg_field=log.msg&_time_field=timestamp"
encoding.codec = "json"
framing.method = "newline_delimited"
compression = "gzip"
healthcheck.enabled = false
[sinks.vlogs.query]
_msg_field = "log.msg"
_time_field = "timestamp"
_stream_fields = "source_type,host,container_name"
[sinks.vlogs.request.headers]
AccountID = "0"
ProjectID = "0"

View File

@@ -1,7 +1,7 @@
services:
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.100.0
image: victoriametrics/vmagent:v1.100.1
depends_on:
- "victoriametrics"
ports:
@@ -18,7 +18,7 @@ services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- 8428:8428
volumes:
@@ -51,7 +51,7 @@ services:
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.100.0
image: victoriametrics/vmalert:v1.100.1
depends_on:
- "victoriametrics"
ports:

View File

@@ -46,7 +46,7 @@ services:
- '--config=/config.yml'
vmsingle:
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- '8428:8428'
command:

View File

@@ -19,8 +19,8 @@ On the server:
* VictoriaMetrics is running on ports: 8428, 8089, 4242, 2003 and they are bound to the local interface.
********************************************************************************
# This image includes v1.100.0 release of VictoriaMetrics.
# See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.0
# This image includes v1.100.1 release of VictoriaMetrics.
# See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1
# Welcome to VictoriaMetrics droplet!

View File

@@ -30,11 +30,15 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
## tip
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): supported any status codes from the range 200-299 from alertmanager. Previously, only 200 status code considered a successful action. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6110).
* BUGFIX: [vmauth](https://docs.victoriametrics.com/vmauth/): don't treat concurrency limit hit as an error of the backend. Previously, hitting the concurrency limit would increment both `vmauth_concurrent_requests_limit_reached_total` and `vmauth_user_request_backend_errors_total` counters. Now, only concurrency limit counter is incremented. Updates [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5565).
## [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1)
Released at 2024-04-11
**Update note 1: When upgrading to this release from [v1.99.0](https://docs.victoriametrics.com/changelog/#v1990) or [v1.100.0](https://docs.victoriametrics.com/changelog/#v11000) it is recommended to reset caches stored on disk according to [these](https://docs.victoriametrics.com/single-server-victoriametrics/#cache-removal) docs.**
* FEATURE: [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager.html): allow specifying custom backup interval via `-backupInterval` command-line flag. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5966).
* BUGFIX: properly register new entries in IndexDB when many new time series are ingested into VictoriaMetrics in a short period of time. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5959) and [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6069) issues. The bug has been introduced in [v1.99.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.99.0).
@@ -44,7 +48,7 @@ Released at 2024-04-11
Released at 2024-04-04
**This release contains [the issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5959), which can prevent from storing data for new time series under high rate of search queries. Please upgrade to [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1).**
**This release contains [the issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5959), which can prevent from storing data for new time series under high rate of search queries. Please rollback to [v1.98.0](https://docs.victoriametrics.com/changelog/#v1980) or upgrade to [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1).**
**Update note 1: the `-datasource.lookback` command-line flag at `vmalert` is no-op starting from this release. This flag will be removed in the future, so please switch to [`eval_delay` option](https://docs.victoriametrics.com/vmalert/#groups). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5155) for more details.**
@@ -102,7 +106,7 @@ Released at 2024-04-04
Released at 2024-03-01
**This release contains [the issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5959), which can prevent from storing data for new time series under high rate of search queries. Please upgrade to [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1).**
**This release contains [the issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5959), which can prevent from storing data for new time series under high rate of search queries. Please rollback to [v1.98.0](https://docs.victoriametrics.com/changelog/#v1980) or upgrade to [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1).**
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): propagate [label filters](https://docs.victoriametrics.com/keyconcepts/#filtering) via all the [label manipulation functions](https://docs.victoriametrics.com/metricsql/#label-manipulation-functions). For example, `label_del(some_metric{job="foo"}, "instance") + other_metric{pod="bar"}` is now transformed to `label_del(some_metric{job="foo",pod="bar"}, "instance") + other_metric{job="foo",pod="bar"}`. This should reduce the amounts of time series processed during query execution.
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add [count_values_over_time](https://docs.victoriametrics.com/MetricsQL.html#count_values_over_time) function. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5847).

View File

@@ -459,8 +459,8 @@ Cluster performance and capacity can be scaled up in two ways:
General recommendations for cluster scalability:
- Adding more CPU and RAM to existing `vmselect` nodes improves the performance for heavy queries, which process big number of time series with big number of raw samples. See [this article on how to detect and optimize heavy queries](https://valyala.medium.com/how-to-optimize-promql-and-metricsql-queries-85a1b75bf986).
- Adding more `vmstorage` nodes increases the number of [active time series](https://docs.victoriametrics.com/FAQ.html#what-is-an-active-time-series) the cluster can handle. This also increases query performance over time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). The cluster stability is also improved with the number of `vmstorage` nodes, since active `vmstorage` nodes need to handle lower additional workload when some of `vmstorage` nodes become unavailable.
- Adding more CPU and RAM to existing `vmstorage` nodes increases the number of [active time series](https://docs.victoriametrics.com/FAQ.html#what-is-an-active-time-series) the cluster can handle. It is preferred to add more `vmstorage` nodes over adding more CPU and RAM to existing `vmstorage` nodes, since higher number of `vmstorage` nodes increases cluster stability and improves query performance over time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate).
- Adding more `vmstorage` nodes (aka horizontal scaling) increases the number of [active time series](https://docs.victoriametrics.com/FAQ.html#what-is-an-active-time-series) the cluster can handle. This also increases query performance over time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). The cluster stability is also improved with the number of `vmstorage` nodes, since active `vmstorage` nodes need to handle lower additional workload when some of `vmstorage` nodes become unavailable. For example, during a node outage the rest of the nodes will pick up the load designated to unavailable node. So in case one node out of 5 is unavailable 20% of the load will be re-distributed across 4 remaining nodes which means each node will take 5% of the load. With 10 nodes in case of outage 10% of the load will be distributed across 9 remaining node, so around ~1% of load will be distributed across other nodes.
- Adding more CPU and RAM to existing `vmstorage` nodes (aka vertical scaling) increases the number of [active time series](https://docs.victoriametrics.com/FAQ.html#what-is-an-active-time-series) the cluster can handle. It is preferred to add more `vmstorage` nodes over adding more CPU and RAM to existing `vmstorage` nodes, since higher number of `vmstorage` nodes increases cluster stability and improves query performance over time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate).
- Adding more `vminsert` nodes increases the maximum possible data ingestion speed, since the ingested data may be split among bigger number of `vminsert` nodes.
- Adding more `vmselect` nodes increases the maximum possible queries rate, since the incoming concurrent requests may be split among bigger number of `vmselect` nodes.
@@ -470,6 +470,8 @@ Steps to add `vmstorage` node:
1. Gradually restart all the `vmselect` nodes with new `-storageNode` arg containing `<new_vmstorage_host>`.
1. Gradually restart all the `vminsert` nodes with new `-storageNode` arg containing `<new_vmstorage_host>`.
In order to handle uneven disk space usage distribution after adding new `vmstorage` node it is possible to update `vminsert` configuration to route newly ingested metrics only to new storage nodes. Once disk usage will be similar configuration can be updated to include all nodes again. Note that `vmselect` nodes need to reference all storage nodes for querying.
## Updating / reconfiguring cluster nodes
All the node types - `vminsert`, `vmselect` and `vmstorage` - may be updated via graceful shutdown.

View File

@@ -119,7 +119,7 @@ VictoriaMetrics ecosystem contains the following components additionally to [sin
- [vmalert](https://docs.victoriametrics.com/vmalert/) - a service for processing Prometheus-compatible alerting and recording rules.
- [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/) - a tool for validating alerting and recording rules.
- [vmauth](https://docs.victoriametrics.com/vmauth/) - authorization proxy and load balancer optimized for VictoriaMetrics products.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - auhtorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - authorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmctl](https://docs.victoriametrics.com/vmctl/) - a tool for migrating and copying data between different storage systems for metrics.
- [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmrestore](https://docs.victoriametrics.com/vmrestore/) and [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/) -
tools for creating backups and restoring from backups for VictoriaMetrics data.
@@ -2420,7 +2420,7 @@ It is also possible removing [rollup result cache](#rollup-result-cache) on star
## Rollup result cache
VictoriaMetrics caches query reponses by default. This allows increasing performance for repated queries
VictoriaMetrics caches query responses by default. This allows increasing performance for repated queries
to [`/api/v1/query`](https://docs.victoriametrics.com/keyconcepts/#instant-query) and [`/api/v1/query_range`](https://docs.victoriametrics.com/keyconcepts/#range-query)
with the increasing `time`, `start` and `end` query args.

View File

@@ -52,7 +52,7 @@ Bumping the limits may significantly improve build speed.
Ideally, every change must be documented in the commit with the change. Alternatively, the change must be documented immediately
after the commit, which adds the change.
1. Make sure all the changes are synced between `master`, `cluster`, `enterprise-single-node` and `enteprise-cluster` branches.
Changes in these branches must be synced immediately after they are commited in at least a single branch.
Changes in these branches must be synced immediately after they are committed in at least a single branch.
1. Make sure that the release branches have no security issues.
1. Update release versions if needed in [SECURITY.md](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/SECURITY.md).
1. Add `(available starting from v1.xx.y)` line to feature docs introduced in the upcoming release.

View File

@@ -127,7 +127,7 @@ VictoriaMetrics ecosystem contains the following components additionally to [sin
- [vmalert](https://docs.victoriametrics.com/vmalert/) - a service for processing Prometheus-compatible alerting and recording rules.
- [vmalert-tool](https://docs.victoriametrics.com/vmalert-tool/) - a tool for validating alerting and recording rules.
- [vmauth](https://docs.victoriametrics.com/vmauth/) - authorization proxy and load balancer optimized for VictoriaMetrics products.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - auhtorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmgateway](https://docs.victoriametrics.com/vmgateway/) - authorization proxy with per-[tenant](https://docs.victoriametrics.com/cluster-victoriametrics/#multitenancy) rate limiting cababilities.
- [vmctl](https://docs.victoriametrics.com/vmctl/) - a tool for migrating and copying data between different storage systems for metrics.
- [vmbackup](https://docs.victoriametrics.com/vmbackup/), [vmrestore](https://docs.victoriametrics.com/vmrestore/) and [vmbackupmanager](https://docs.victoriametrics.com/vmbackupmanager/) -
tools for creating backups and restoring from backups for VictoriaMetrics data.
@@ -2428,7 +2428,7 @@ It is also possible removing [rollup result cache](#rollup-result-cache) on star
## Rollup result cache
VictoriaMetrics caches query reponses by default. This allows increasing performance for repated queries
VictoriaMetrics caches query responses by default. This allows increasing performance for repated queries
to [`/api/v1/query`](https://docs.victoriametrics.com/keyconcepts/#instant-query) and [`/api/v1/query_range`](https://docs.victoriametrics.com/keyconcepts/#range-query)
with the increasing `time`, `start` and `end` query args.

View File

@@ -269,5 +269,5 @@ Here is the list of log collectors and their ingestion formats supported by Vict
| [Filebeat](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Filebeat.html) | [Yes](https://www.elastic.co/guide/en/beats/filebeat/current/elasticsearch-output.html) | No | No |
| [Fluentbit](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Fluentbit.html) | No | [Yes](https://docs.fluentbit.io/manual/pipeline/outputs/http) | [Yes](https://docs.fluentbit.io/manual/pipeline/outputs/loki) |
| [Logstash](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Logstash.html) | [Yes](https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html) | No | No |
| [Vector](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Vector.html) | [Yes](https://vector.dev/docs/reference/configuration/sinks/elasticsearch/) | No | [Yes](https://vector.dev/docs/reference/configuration/sinks/loki/) |
| [Vector](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Vector.html) | [Yes](https://vector.dev/docs/reference/configuration/sinks/elasticsearch/) | [Yes](https://vector.dev/docs/reference/configuration/sinks/http/) | [Yes](https://vector.dev/docs/reference/configuration/sinks/loki/) |
| [Promtail](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/Promtail.html) | No | No | [Yes](https://grafana.com/docs/loki/latest/clients/promtail/configuration/#clients) |

View File

@@ -11,6 +11,9 @@ aliases:
---
# Vector setup
## Elasticsearch sink
Specify [Elasticsearch sink type](https://vector.dev/docs/reference/configuration/sinks/elasticsearch/) in the `vector.toml`
for sending the collected logs to [VictoriaLogs](https://docs.victoriametrics.com/VictoriaLogs/):
@@ -140,6 +143,25 @@ For example, the following `vector.toml` config instructs Vector to store the da
ProjectID = "34"
```
## HTTP sink
Vector can be configured with [HTTP](https://vector.dev/docs/reference/configuration/sinks/http/) sink type
for sending data to [JSON stream API](https://docs.victoriametrics.com/victorialogs/data-ingestion/#json-stream-api):
```toml
[sinks.vlogs]
inputs = [ "your_input" ]
type = "http"
uri = "http://localhost:9428/insert/jsonline?_stream_fields=host,container_name&_msg_field=message&_time_field=timestamp"
encoding.codec = "json"
framing.method = "newline_delimited"
healthcheck.enabled = false
[sinks.vlogs.request.headers]
AccountID = "12"
ProjectID = "34"
```
See also:
- [Data ingestion troubleshooting](https://docs.victoriametrics.com/VictoriaLogs/data-ingestion/#troubleshooting).

View File

@@ -19,9 +19,9 @@ aliases:
- To use *vmanomaly*, part of the enterprise package, a license key is required. Obtain your key [here](https://victoriametrics.com/products/enterprise/trial/) for this tutorial or for enterprise use.
- In the tutorial, we'll be using the following VictoriaMetrics components:
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html) (v1.100.0)
- [vmalert](https://docs.victoriametrics.com/vmalert.html) (v1.100.0)
- [vmagent](https://docs.victoriametrics.com/vmagent.html) (v1.100.0)
- [VictoriaMetrics Single-Node](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html) (v1.100.1)
- [vmalert](https://docs.victoriametrics.com/vmalert.html) (v1.100.1)
- [vmagent](https://docs.victoriametrics.com/vmagent.html) (v1.100.1)
- [Grafana](https://grafana.com/) (v.10.2.1)
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/)
- [Node exporter](https://github.com/prometheus/node_exporter#node-exporter) (v1.7.0) and [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) (v0.27.0)
@@ -328,7 +328,7 @@ Let's wrap it all up together into the `docker-compose.yml` file.
services:
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.100.0
image: victoriametrics/vmagent:v1.100.1
depends_on:
- "victoriametrics"
ports:
@@ -345,7 +345,7 @@ services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- 8428:8428
volumes:
@@ -378,7 +378,7 @@ services:
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.100.0
image: victoriametrics/vmalert:v1.100.1
depends_on:
- "victoriametrics"
ports:

View File

@@ -84,7 +84,7 @@ VictoriaMetrics Enterprise components are available in the following forms:
It is allowed to run VictoriaMetrics Enterprise components in [cases listed here](#valid-cases-for-victoriametrics-enterprise).
Binary releases of VictoriaMetrics Enterprise are available [at the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest).
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.100.0-enterprise.tar.gz`.
Enterprise binaries and packages have `enterprise` suffix in their names. For example, `victoria-metrics-linux-amd64-v1.100.1-enterprise.tar.gz`.
In order to run binary release of VictoriaMetrics Enterprise component, please download the `*-enterprise.tar.gz` archive for your OS and architecture
from the [releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/latest) and unpack it. Then run the unpacked binary.
@@ -101,8 +101,8 @@ For example, the following command runs VictoriaMetrics Enterprise binary with t
obtained at [this page](https://victoriametrics.com/products/enterprise/trial/):
```sh
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.0/victoria-metrics-linux-amd64-v1.100.0-enterprise.tar.gz
tar -xzf victoria-metrics-linux-amd64-v1.100.0-enterprise.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.1/victoria-metrics-linux-amd64-v1.100.1-enterprise.tar.gz
tar -xzf victoria-metrics-linux-amd64-v1.100.1-enterprise.tar.gz
./victoria-metrics-prod -license=BASE64_ENCODED_LICENSE_KEY
```
@@ -117,7 +117,7 @@ Alternatively, VictoriaMetrics Enterprise license can be stored in the file and
It is allowed to run VictoriaMetrics Enterprise components in [cases listed here](#valid-cases-for-victoriametrics-enterprise).
Docker images for VictoriaMetrics Enterprise are available [at VictoriaMetrics DockerHub](https://hub.docker.com/u/victoriametrics).
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.100.0-enteprise`.
Enterprise docker images have `enterprise` suffix in their names. For example, `victoriametrics/victoria-metrics:v1.100.1-enterprise`.
In order to run Docker image of VictoriaMetrics Enterprise component, it is required to provide the license key via command-line
flag as described [here](#binary-releases).
@@ -127,13 +127,13 @@ Enterprise license key can be obtained at [this page](https://victoriametrics.co
For example, the following command runs VictoriaMetrics Enterprise Docker image with the specified license key:
```sh
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.100.0-enteprise -license=BASE64_ENCODED_LICENSE_KEY
docker run --name=victoria-metrics victoriametrics/victoria-metrics:v1.100.1-enterprise -license=BASE64_ENCODED_LICENSE_KEY
```
Alternatively, the license code can be stored in the file and then referred via `-licenseFile` command-line flag:
```sh
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.100.0-enteprise -licenseFile=/path/to/vm-license
docker run --name=victoria-metrics -v /vm-license:/vm-license victoriametrics/victoria-metrics:v1.100.1-enterprise -licenseFile=/path/to/vm-license
```
Example docker-compose configuration:
@@ -142,7 +142,7 @@ version: "3.5"
services:
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.100.0
image: victoriametrics/victoria-metrics:v1.100.1
ports:
- 8428:8428
volumes:
@@ -174,7 +174,7 @@ is used to provide key in plain-text:
```yaml
server:
image:
tag: v1.100.0-enterprise
tag: v1.100.1-enterprise
license:
key: {BASE64_ENCODED_LICENSE_KEY}
@@ -185,7 +185,7 @@ In order to provide key via existing secret, the following values file is used:
```yaml
server:
image:
tag: v1.100.0-enterprise
tag: v1.100.1-enterprise
license:
secret:
@@ -232,7 +232,7 @@ spec:
license:
key: {BASE64_ENCODED_LICENSE_KEY}
image:
tag: v1.100.0-enterprise
tag: v1.100.1-enterprise
```
In order to provide key via existing secret, the following custom resource is used:
@@ -249,7 +249,7 @@ spec:
name: vm-license
key: license
image:
tag: v1.100.0-enterprise
tag: v1.100.1-enterprise
```
Example secret with license key:

View File

@@ -137,7 +137,7 @@ groups:
Upload rules to the Managed VictoriaMetrics using the following command:
```sh
curl https://https://cloud.victoriametrics.com/api/v1/deployments/DEPLOYMENT_ID/rule-sets/files/testing-rules -v -H 'X-VM-Cloud-Access: CLOUD_API_TOKEN' -XPOST --data-binary '@testing-rules.yaml'
curl https://cloud.victoriametrics.com/api/v1/deployments/DEPLOYMENT_ID/rule-sets/files/testing-rules -v -H 'X-VM-Cloud-Access: CLOUD_API_TOKEN' -XPOST --data-binary '@testing-rules.yaml'
```
## Troubleshooting

View File

@@ -16,14 +16,31 @@ aliases:
## Next release
**Update note: [vmcluster](./api.md#vmcluster): remove fields `VMClusterSpec.VMInsert.Name`, `VMClusterSpec.VMStorage.Name`, `VMClusterSpec.VMSelect.Name`, they're marked as deprecated since v0.21.0. See [this pull request](https://github.com/VictoriaMetrics/operator/pull/907).**
**Update note: PodSecurityPolicy supports was deleted. Operator no long creates PSP related objects since it's no longer supported by Kubernetes actual versions. See this [doc](https://kubernetes.io/blog/2021/04/08/kubernetes-1-21-release-announcement/#podsecuritypolicy-deprecation) for details.**
**Update note: PodDisruptionBudget at betav1 API is no longer supported. Operator uses v1 stable version. See this [doc](https://kubernetes.io/docs/reference/using-api/deprecation-guide/#poddisruptionbudget-v125) for details.**
**Update note: `Alertmanager` versions below `v0.22.0` are no longer supported. Version must upgraded - manually for resources or use default version bundled with operator config.**
- [operator](./README.md): properly reconcile `ServiceAccount` specified for `CRD`s. Previously operator didn't perform a check for actual owner of `ServiceAccount`. Now it creates and updates `ServiceAccount` only if this field is omitted at `CRD` definition. It fixes possible ownership race conditions.
- Update VictoriaMetrics image tags to [v1.100.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.100.1).
- [operator](./README.md): reduce number of watched resources owned by `CRD`s. Operator no longer watches for `Service`, `Secret`, `Configmap` changes owned by CRD object. It must reduce logging output, CPU and memory usage for operator.
- [operator](./README.md): exposes `config-reloader-http` port with `8435` number for the customer config-reloader containers. Operator may use own config-reloader implementation for `VMAuth`, `VMAlertmanager` and `VMAgent`.
- [operator](./README.md): adds new field `configReloaderExtraArgs` for `VMAgent`, `VMAlert`, `VMAuth` and `VMAlertmanager` CRDs. It allows to configure config-reloader container.
- [config-reloader](./README.md): adds error metrics to the config-reloader container - `configreloader_last_reload_successful`, `configreloader_last_reload_errors_total`, `configreloader_config_last_reload_total`, `configreloader_k8s_watch_errors_total`, `configreloader_secret_content_update_errors_total`, `configreloader_last_reload_success_timestamp_seconds`. See this [issue](https://github.com/VictoriaMetrics/operator/issues/916) for details.
- [operator](./README.md): Changes error handling for reconcile. Operator sends `Events` into kubernetes API, if any error happened during object reconcile. See this [issue](https://github.com/VictoriaMetrics/operator/issues/900) for details.
- [operator](./README.md): updates base Docker image and prometheus_client to versions with with CVE fixes
- [operator](./README.md): adds reconcile retries on conflict for `Service` reconcilation. See this [issue](https://github.com/VictoriaMetrics/operator/issues/901) for details.
- [operator](./README.md): adds reconcile retries on conflicts. See this [issue](https://github.com/VictoriaMetrics/operator/issues/901) for details.
- [operator](./README.md): allows adjust `Service` generated by operator with `useAsDefault` option set to `true` for `serviceSpec` field. See this [issue](https://github.com/VictoriaMetrics/operator/issues/904) for details.
- [vmagent](./api.md#vmagent): change service for `statefulMode` to the `headless` instead of `clusterIP`. See this [issue](https://github.com/VictoriaMetrics/operator/issues/917) for details.
- [vmservicescrape&vmpodscrape](./api.md#vmservicescrape): add `attach_metadata` option under VMServiceScrapeSpec&VMPodScrapeSpec, the same way like prometheus serviceMonitor&podMonitor do. See [this issue](https://github.com/VictoriaMetrics/operator/issues/893) for details.
- [vmalertmanagerconfig](./api.md#vmalertmanagerconfig): fix struct field tags under `Sigv4Config`.
- [vmalertmanagerconfig](./api.md#vmalertmanagerconfig): adds own `config-reloader` container. It must improve speed of config updates. See [this issue](https://github.com/VictoriaMetrics/operator/issues/915) for details.
- [vmalertmanager](./api.md#vmalertmanager): bump default alertmanager version to [v0.27.0](https://github.com/prometheus/alertmanager/releases/tag/v0.27.0), which supports new receivers like `msteams_configs`.
- [vmalertmanager](./api.md#vmalertmanager): supports alertmanager version v0.22.0 or higher. Previous versions are no longer supported and must be upgraded before using new operator release.
- [vmscrapeconfig](./api.md#vmscrapeconfig): add crd VMScrapeConfig, which can define a scrape config using any of the service discovery options supported in victoriametrics.
- [vmprobe](./api.md#vmprobe): add field `proxy_url`, see [this issue](https://github.com/VictoriaMetrics/operator/issues/731) for details.
- scrape CRDs: add field `series_limit`, which can be used to limit the number of unique time series a single scrape target can expose.
- scrape CRDs: fix scrape_config filed `disable_keep_alive`, before it's misconfigured as `disable_keepalive` and won't work.
- scrape CRDs: deprecated option `relabel_debug` and `metric_relabel_debug`, they were deprecated since [v1.85.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.85.0).
<a name="v0.42.3"></a>
## [v0.43.](https://github.com/VictoriaMetrics/operator/releases/tag/v0.42.3) - 12 Mar 2024

View File

@@ -130,6 +130,7 @@ This Document documents the types introduced by the VictoriaMetrics to be consum
* [CRDRef](#crdref)
* [StaticRef](#staticref)
* [TargetRef](#targetref)
* [TargetRefBasicAuth](#targetrefbasicauth)
* [VMUser](#vmuser)
* [VMUserIPFilters](#vmuseripfilters)
* [VMUserList](#vmuserlist)
@@ -230,6 +231,7 @@ VMAlertmanagerSpec is a specification of the desired behavior of the VMAlertmana
| selectAllByDefault | SelectAllByDefault changes default behavior for empty CRD selectors, such ConfigSelector. with selectAllByDefault: true and undefined ConfigSelector and ConfigNamespaceSelector Operator selects all exist alertManagerConfigs with selectAllByDefault: false - selects nothing | bool | false |
| configSelector | ConfigSelector defines selector for VMAlertmanagerConfig, result config will be merged with with Raw or Secret config. Works in combination with NamespaceSelector. NamespaceSelector nil - only objects at VMAlertmanager namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| configNamespaceSelector | \n ConfigNamespaceSelector defines namespace selector for VMAlertmanagerConfig.\nWorks in combination with Selector. NamespaceSelector nil - only objects at VMAlertmanager namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| configReloaderExtraArgs | ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container for example resyncInterval: \&#34;30s\&#34; | map[string]string | false |
| extraArgs | ExtraArgs that will be passed to VMAlertmanager pod for example log.level: debug | map[string]string | false |
| extraEnvs | ExtraEnvs that will be added to VMAlertmanager pod | [][v1.EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#envvar-v1-core) | false |
| disableNamespaceMatcher | DisableNamespaceMatcher disables namespace label matcher for VMAlertmanagerConfig It may be useful if alert doesn&#39;t have namespace label for some reason | bool | false |
@@ -870,11 +872,14 @@ VMAgentSpec defines the desired state of VMAgent
| nodeScrapeNamespaceSelector | NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery. Works in combination with Selector. NamespaceSelector nil - only objects at VMAgent namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| staticScrapeSelector | StaticScrapeSelector defines PodScrapes to be selected for target discovery. Works in combination with NamespaceSelector. If both nil - match everything. NamespaceSelector nil - only objects at VMAgent namespace. Selector nil - only objects at NamespaceSelector namespaces. | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| staticScrapeNamespaceSelector | StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery. Works in combination with NamespaceSelector. NamespaceSelector nil - only objects at VMAgent namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| scrapeConfigSelector | ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery. Works in combination with NamespaceSelector. | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| scrapeConfigNamespaceSelector | ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery. Works in combination with Selector. NamespaceSelector nil - only objects at VMAgent namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| inlineScrapeConfig | InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it is valid. Note that using this feature may expose the possibility to break upgrades of VMAgent. It is advised to review VMAgent release notes to ensure that no incompatible scrape configs are going to break VMAgent after the upgrade. it should be defined as single yaml file. inlineScrapeConfig: \|\n - job_name: \&#34;prometheus\&#34;\n static_configs:\n - targets: [\&#34;localhost:9090\&#34;] | string | false |
| additionalScrapeConfigs | AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it is valid. Note that using this feature may expose the possibility to break upgrades of VMAgent. It is advised to review VMAgent release notes to ensure that no incompatible scrape configs are going to break VMAgent after the upgrade. | *[v1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#secretkeyselector-v1-core) | false |
| arbitraryFSAccessThroughSMs | ArbitraryFSAccessThroughSMs configures whether configuration based on a service scrape can access arbitrary files on the file system of the VMAgent container e.g. bearer token files. | [ArbitraryFSAccessThroughSMsConfig](#arbitraryfsaccessthroughsmsconfig) | false |
| insertPorts | InsertPorts - additional listen ports for data ingestion. | *[InsertPorts](#insertports) | false |
| port | Port listen address | string | false |
| configReloaderExtraArgs | ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container for example resyncInterval: \&#34;30s\&#34; | map[string]string | false |
| extraArgs | ExtraArgs that will be passed to VMAgent pod for example remoteWrite.tmpDataPath: /tmp it would be converted to flag --remoteWrite.tmpDataPath=/tmp | map[string]string | false |
| extraEnvs | ExtraEnvs that will be added to VMAgent pod | [][v1.EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#envvar-v1-core) | false |
| serviceSpec | ServiceSpec that will be added to vmagent service spec | *[AdditionalServiceSpec](#additionalservicespec) | false |
@@ -892,6 +897,7 @@ VMAgentSpec defines the desired state of VMAgent
| nodeScrapeRelabelTemplate | NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape. it&#39;s useful for adding specific labels to all targets | []*[RelabelConfig](#relabelconfig) | false |
| staticScrapeRelabelTemplate | StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape. it&#39;s useful for adding specific labels to all targets | []*[RelabelConfig](#relabelconfig) | false |
| probeScrapeRelabelTemplate | ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape. it&#39;s useful for adding specific labels to all targets | []*[RelabelConfig](#relabelconfig) | false |
| scrapeConfigRelabelTemplate | ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig. it&#39;s useful for adding specific labels to all targets | []*[RelabelConfig](#relabelconfig) | false |
| minScrapeInterval | MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes If interval is lower than defined limit, `minScrapeInterval` will be used. | *string | false |
| maxScrapeInterval | MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes If interval is higher than defined limit, `maxScrapeInterval` will be used. | *string | false |
| terminationGracePeriodSeconds | TerminationGracePeriodSeconds period for container graceful termination | *int64 | false |
@@ -1259,6 +1265,7 @@ VMAlertSpec defines the desired state of VMAlert
| remoteRead | RemoteRead Optional URL to read vmalert state (persisted via RemoteWrite) This configuration only makes sense if alerts state has been successfully persisted (via RemoteWrite) before. see -remoteRead.url docs in vmalerts for details. E.g. http://127.0.0.1:8428 | *[VMAlertRemoteReadSpec](#vmalertremotereadspec) | false |
| rulePath | RulePath to the file with alert rules. Supports patterns. Flag can be specified multiple times. Examples: -rule /path/to/file. Path to a single file with alerting rules -rule dir/*.yaml -rule /*.yaml. Relative path to all .yaml files in folder, absolute path to all .yaml files in root. by default operator adds /etc/vmalert/configs/base/vmalert.yaml | []string | false |
| datasource | Datasource Victoria Metrics or VMSelect url. Required parameter. e.g. http://127.0.0.1:8428 | [VMAlertDatasourceSpec](#vmalertdatasourcespec) | true |
| configReloaderExtraArgs | ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container for example resyncInterval: \&#34;30s\&#34; | map[string]string | false |
| extraArgs | ExtraArgs that will be passed to VMAlert pod for example -remoteWrite.tmpDataPath=/tmp | map[string]string | false |
| extraEnvs | ExtraEnvs that will be added to VMAlert pod | [][v1.EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#envvar-v1-core) | false |
| externalLabels | ExternalLabels in the form &#39;name: value&#39; to add to all generated recording rules and alerts. | map[string]string | false |
@@ -1514,6 +1521,7 @@ Endpoint defines a scrapeable endpoint serving Prometheus metrics.
| scrape_interval | ScrapeInterval is the same as Interval and has priority over it. one of scrape_interval or interval can be used | string | false |
| scrapeTimeout | Timeout after which the scrape is ended | string | false |
| sampleLimit | SampleLimit defines per-endpoint limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| oauth2 | OAuth2 defines auth configuration | *[OAuth2](#oauth2) | false |
| authorization | Authorization with http header Authorization | *[Authorization](#authorization) | false |
| tlsConfig | TLSConfig configuration to use when scraping the endpoint | *[TLSConfig](#tlsconfig) | false |
@@ -1624,10 +1632,10 @@ VMScrapeParams defines scrape target configuration that compatible only with Vic
| Field | Description | Scheme | Required |
| ----- | ----------- | ------ | -------- |
| relabel_debug | | *bool | false |
| metric_relabel_debug | | *bool | false |
| relabel_debug | deprecated since [v1.85](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.85.0), will be removed in next release | *bool | false |
| metric_relabel_debug | deprecated since [v1.85](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.85.0), will be removed in next release | *bool | false |
| disable_compression | | *bool | false |
| disable_keep_alive | | *bool | false |
| disable_keep_alive | disable_keepalive allows disabling HTTP keep-alive when scraping targets. By default, HTTP keep-alive is enabled, so TCP connections to scrape targets could be re-used. See https://docs.victoriametrics.com/vmagent.html#scrape_config-enhancements | *bool | false |
| no_stale_markers | | *bool | false |
| stream_parse | | *bool | false |
| scrape_align_interval | | *string | false |
@@ -1674,6 +1682,7 @@ VMServiceScrapeSpec defines the desired state of VMServiceScrape
| selector | Selector to select Endpoints objects by corresponding Service labels. | [metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| namespaceSelector | Selector to select which namespaces the Endpoints objects are discovered from. | [NamespaceSelector](#namespaceselector) | false |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| attach_metadata | AttachMetadata configures metadata attaching from service discovery | [AttachMetadata](#attachmetadata) | false |
[Back to TOC](#table-of-contents)
@@ -1704,6 +1713,7 @@ PodMetricsEndpoint defines a scrapeable endpoint of a Kubernetes Pod serving Pro
| scrape_interval | ScrapeInterval is the same as Interval and has priority over it. one of scrape_interval or interval can be used | string | false |
| scrapeTimeout | Timeout after which the scrape is ended | string | false |
| sampleLimit | SampleLimit defines per-podEndpoint limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| honorLabels | HonorLabels chooses the metric&#39;s labels on collisions with target labels. | bool | false |
| honorTimestamps | HonorTimestamps controls whether vmagent respects the timestamps present in scraped data. | *bool | false |
| metricRelabelConfigs | MetricRelabelConfigs to apply to samples before ingestion. | []*[RelabelConfig](#relabelconfig) | false |
@@ -1756,6 +1766,7 @@ VMPodScrapeSpec defines the desired state of VMPodScrape
| selector | Selector to select Pod objects. | [metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| namespaceSelector | Selector to select which namespaces the Endpoints objects are discovered from. | [NamespaceSelector](#namespaceselector) | false |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| attach_metadata | AttachMetadata configures metadata attaching from service discovery | [AttachMetadata](#attachmetadata) | false |
[Back to TOC](#table-of-contents)
@@ -2099,6 +2110,7 @@ VMNodeScrapeSpec defines specification for VMNodeScrape.
| proxyURL | ProxyURL eg http://proxyserver:2195 Directs scrapes to proxy through this endpoint. | *string | false |
| selector | Selector to select kubernetes Nodes. | [metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| vm_scrape_params | VMScrapeParams defines VictoriaMetrics specific scrape parametrs | *[VMScrapeParams](#vmscrapeparams) | false |
[Back to TOC](#table-of-contents)
@@ -2142,6 +2154,18 @@ TargetRef describes target for user traffic forwarding. one of target types can
| retry_status_codes | RetryStatusCodes defines http status codes in numeric format for request retries Can be defined per target or at VMUser.spec level e.g. [429,503] | []int | false |
| load_balancing_policy | LoadBalancingPolicy defines load balancing policy to use for backend urls. Supported policies: least_loaded, first_available. See https://docs.victoriametrics.com/vmauth.html#load-balancing for more details (default \&#34;least_loaded\&#34;) | *string | false |
| drop_src_path_prefix_parts | DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. See https://docs.victoriametrics.com/vmauth.html#dropping-request-path-prefix for more details. | *int | false |
| targetRefBasicAuth | TargetRefBasicAuth allow an target endpoint to authenticate over basic authentication | *[TargetRefBasicAuth](#targetrefbasicauth) | false |
[Back to TOC](#table-of-contents)
## TargetRefBasicAuth
TargetRefBasicAuth target basic authentication
| Field | Description | Scheme | Required |
| ----- | ----------- | ------ | -------- |
| username | The secret in the service scrape namespace that contains the username for authentication. It must be at them same namespace as CRD | [v1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#secretkeyselector-v1-core) | true |
| password | The secret in the service scrape namespace that contains the password for authentication. It must be at them same namespace as CRD | [v1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#secretkeyselector-v1-core) | true |
[Back to TOC](#table-of-contents)
@@ -2286,6 +2310,7 @@ VMAuthSpec defines the desired state of VMAuth
| selectAllByDefault | SelectAllByDefault changes default behavior for empty CRD selectors, such userSelector. with selectAllByDefault: true and empty userSelector and userNamespaceSelector Operator selects all exist users with selectAllByDefault: false - selects nothing | bool | false |
| userSelector | UserSelector defines VMUser to be selected for config file generation. Works in combination with NamespaceSelector. NamespaceSelector nil - only objects at VMAuth namespace. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| userNamespaceSelector | UserNamespaceSelector Namespaces to be selected for VMAuth discovery. Works in combination with Selector. NamespaceSelector nil - only objects at VMAuth namespace. Selector nil - only objects at NamespaceSelector namespaces. If both nil - behaviour controlled by selectAllByDefault | *[metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta) | false |
| configReloaderExtraArgs | ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container for example resyncInterval: \&#34;30s\&#34; | map[string]string | false |
| extraArgs | ExtraArgs that will be passed to VMAuth pod for example remoteWrite.tmpDataPath: /tmp | map[string]string | false |
| extraEnvs | ExtraEnvs that will be added to VMAuth pod | [][v1.EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#envvar-v1-core) | false |
| serviceSpec | ServiceSpec that will be added to vmsingle service spec | *[AdditionalServiceSpec](#additionalservicespec) | false |
@@ -2348,6 +2373,7 @@ TargetEndpoint defines single static target endpoint.
| params | Optional HTTP URL parameters | map[string][]string | false |
| follow_redirects | FollowRedirects controls redirects for scraping. | *bool | false |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| interval | Interval at which metrics should be scraped | string | false |
| scrape_interval | ScrapeInterval is the same as Interval and has priority over it. one of scrape_interval or interval can be used | string | false |
| scrapeTimeout | Timeout after which the scrape is ended | string | false |
@@ -2398,6 +2424,7 @@ VMStaticScrapeSpec defines the desired state of VMStaticScrape.
| jobName | JobName name of job. | string | false |
| targetEndpoints | A list of target endpoints to scrape metrics from. | []*[TargetEndpoint](#targetendpoint) | true |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
[Back to TOC](#table-of-contents)
@@ -2452,12 +2479,14 @@ VMProbeSpec contains specification parameters for a Probe.
| params | Optional HTTP URL parameters | map[string][]string | false |
| follow_redirects | FollowRedirects controls redirects for scraping. | *bool | false |
| sampleLimit | SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. | uint64 | false |
| seriesLimit | SeriesLimit defines per-scrape limit on number of unique time series a single target can expose during all the scrapes on the time window of 24h. | uint64 | false |
| bearerTokenFile | File to read bearer token for scraping targets. | string | false |
| bearerTokenSecret | Secret to mount to read bearer token for scraping targets. The secret needs to be in the same namespace as the service scrape and accessible by the victoria-metrics operator. | *[v1.SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#secretkeyselector-v1-core) | false |
| basicAuth | BasicAuth allow an endpoint to authenticate over basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints | *[BasicAuth](#basicauth) | false |
| oauth2 | OAuth2 defines auth configuration | *[OAuth2](#oauth2) | false |
| authorization | Authorization with http header Authorization | *[Authorization](#authorization) | false |
| tlsConfig | TLSConfig configuration to use when scraping the endpoint | *[TLSConfig](#tlsconfig) | false |
| proxyURL | ProxyURL eg http://proxyserver:2195 Directs scrapes to proxy through this endpoint. | *string | false |
| vm_scrape_params | VMScrapeParams defines VictoriaMetrics specific scrape parametrs | *[VMScrapeParams](#vmscrapeparams) | false |
[Back to TOC](#table-of-contents)

View File

@@ -24,6 +24,7 @@ Or you can use VictoriaMetrics CRDs:
- `VMRule` (instead of `PrometheusRule`) - defines alerting or recording rules. [See details](./resources/vmrule.md).
- `VMProbe` (instead of `Probe`) - defines a probing configuration for targets with blackbox exporter. [See details](./resources/vmprobe.md).
- `VMAlertmanagerConfig` (instead of `AlertmanagerConfig`) - defines a configuration for AlertManager. [See details](./resources/vmalertmanagerconfig.md).
- `VMScrapeConfig` (instead of `ScrapeConfig`) - define a scrape config using any of the service discovery options supported in victoriametrics.
Note that Prometheus CRDs are not supplied with the VictoriaMetrics operator,
so you need to [install them separately](https://github.com/prometheus-operator/prometheus-operator/releases).
@@ -33,8 +34,8 @@ and version `monitoring.coreos.com/v1alpha1` for kind `AlertmanagerConfig`.
The default behavior of the operator is as follows:
- It **converts** all existing Prometheus `ServiceMonitor`, `PodMonitor`, `PrometheusRule` and `Probe` objects into corresponding VictoriaMetrics Operator objects.
- It **syncs** updates (including labels) from Prometheus `ServiceMonitor`, `PodMonitor`, `PrometheusRule` and `Probe` objects to corresponding VictoriaMetrics Operator objects.
- It **converts** all existing Prometheus `ServiceMonitor`, `PodMonitor`, `PrometheusRule`, `Probe` and `ScrapeConfig` objects into corresponding VictoriaMetrics Operator objects.
- It **syncs** updates (including labels) from Prometheus `ServiceMonitor`, `PodMonitor`, `PrometheusRule`, `Probe` and `ScrapeConfig` objects to corresponding VictoriaMetrics Operator objects.
- It **DOES NOT delete** converted objects after original ones are deleted.
With this configuration removing prometheus-operator API objects wouldn't delete any converted objects. So you can safely migrate or run two operators at the same time.
@@ -55,6 +56,7 @@ VM_ENABLEDPROMETHEUSCONVERTER_PODMONITOR=false
VM_ENABLEDPROMETHEUSCONVERTER_SERVICESCRAPE=false
VM_ENABLEDPROMETHEUSCONVERTER_PROMETHEUSRULE=false
VM_ENABLEDPROMETHEUSCONVERTER_PROBE=false
VM_ENABLEDPROMETHEUSCONVERTER_SCRAPECONFIG=false
```
For [victoria-metrics-operator helm-chart](https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-metrics-operator/README.md) you can use following way:
@@ -130,6 +132,7 @@ Annotation `operator.victoriametrics.com/ignore-prometheus-updates` can be set o
- [VMRule](./resources/vmrule.md)
- [VMProbe](./resources/vmprobe.md)
- [VMAlertmanagerConfig](./resources/vmalertmanagerconfig.md)
- [VMScrapeConfig](./resources/vmscrapeconfig.md)
And annotation doesn't make sense for [VMStaticScrape](./resources/vmstaticscrape.md)
and [VMNodeScrape](./resources/vmnodescrape.md) because these objects are not created as a result of conversion.
@@ -170,6 +173,7 @@ Annotation `operator.victoriametrics.com/merge-meta-strategy` can be set on one
- [VMRule](./resources/vmrule.md)
- [VMProbe](./resources/vmprobe.md)
- [VMAlertmanagerConfig](./resources/vmalertmanagerconfig.md)
- [VMScrapeConfig](./resources/vmscrapeconfig.md)
And annotation doesn't make sense for [VMStaticScrape](./resources/vmstaticscrape.md)
and [VMNodeScrape](./resources/vmnodescrape.md) because these objects are not created as a result of conversion.

View File

@@ -30,6 +30,7 @@ Metrics Operator introduces.
- [VMStaticScrape](./vmstaticscrape.md)
- [VMSingle](./vmsingle.md)
- [VMUser](./vmuser.md)
- [VMScrapeConfig](./vmscrapeconfig.md)
Here is the scheme of relations between the custom resources:
@@ -119,6 +120,7 @@ Page for every custom resource contains examples section:
- [VMStaticScrape examples](./vmstaticscrape.md#examples)
- [VMSingle examples](./vmsingle.md#examples)
- [VMUser examples](./vmuser.md#examples)
- [VMScrapeConfig examples](./vmscrapeconfig.md#examples)
In addition, you can find examples of the custom resources for VIctoriMetrics operator in
the **[examples directory](https://github.com/VictoriaMetrics/operator/tree/master/config/examples) of operator repository**.

View File

@@ -53,6 +53,7 @@ Also, you can check out the [examples](#examples) section.
- [VMNodeScrape](./vmnodescrape.md),
- [VMStaticScrape](./vmstaticscrape.md),
- [VMProbe](./vmprobe.md).
- `VMScrapeConfig`(./vmscrapeconfig.md)
These objects tell VMAgent from which targets and how to collect metrics and
generate part of [VMAgent](./vmagent.md) scrape configuration.
@@ -65,6 +66,7 @@ Selectors are defined with suffixes - `NamespaceSelector` and `Selector` for eac
- `probeNamespaceSelector` and `probeSelector` for selecting [VMProbe](./vmprobe.md) objects,
- `staticScrapeNamespaceSelector` and `staticScrapeSelector` for selecting [VMStaticScrape](./vmstaticscrape.md) objects,
- `nodeScrapeNamespaceSelector` and `nodeScrapeSelector` for selecting [VMNodeScrape](./vmnodescrape.md) objects.
- `scrapeConfigNamespaceSelector` and `scrapeConfigSelector` for selecting [VMScrapeConfig](./vmscrapeconfig.md) objects.
It allows configuring objects access control across namespaces and different environments.
Specification of selectors you can see in [this doc](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#labelselector-v1-meta).

View File

@@ -51,7 +51,7 @@ spec:
ruleNamespaceSelector: {}
```
[VMRUle](./vmrule.md) objects generate part of `VMAlert` configuration.
[VMRule](./vmrule.md) objects generate part of `VMAlert` configuration.
For filtering rules `VMAlert` uses selectors `ruleNamespaceSelector` and `ruleSelector`.
It allows configuring rules access control across namespaces and different environments.

View File

@@ -0,0 +1,50 @@
---
sort: 15
weight: 15
title: VMServiceScrape
menu:
docs:
parent: "operator-custom-resources"
weight: 15
aliases:
- /operator/resources/vmscrapeconfig.html
---
# VMScrapeConfig
The `VMScrapeConfig` CRD allows to define a scrape config using [any of the service discovery options supported in victoriametrics](https://docs.victoriametrics.com/sd_configs/).
`VMScrapeConfig` object generates part of [VMAgent](./vmagent.md) configuration with Prometheus-compatible scrape targets.
## Specification
You can see the full actual specification of the `VMScrapeConfig` resource in
the **[API docs -> VMScrapeConfig](../api.md#vmscrapeconfig)**.
Also, you can check out the [examples](#examples) section.
## Migration from Prometheus
The `VMScrapeConfig` CRD from VictoriaMetrics Operator is a drop-in replacement
for the Prometheus `ScrapeConfig` from prometheus-operator.
More details about migration from prometheus-operator you can read in [this doc](../migration.md).
## Examples
```yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMScrapeConfig
metadata:
name: mongodb
spec:
consulSDConfigs:
- server: https://consul-dns:8500
services:
- mongodb
relabelConfigs:
- action: replace
sourceLabels:
- __meta_consul_service
targetLabel: job
```

View File

@@ -10,17 +10,17 @@ menu:
<!-- this doc autogenerated - don't edit it manually -->
# Auto Generated vars for package config
updated at Wed Apr 10 20:35:21 UTC 2024
updated at Wed Apr 17 00:50:36 UTC 2024
| varible name | variable default value | variable required | variable description |
| --- | --- | --- | --- |
| VM_USECUSTOMCONFIGRELOADER | false | false | enables custom config reloader for vmauth and vmagent,it should speed-up config reloading process. |
| VM_CONTAINERREGISTRY | - | false | container registry name prefix, e.g. docker.io |
| VM_CUSTOMCONFIGRELOADERIMAGE | victoriametrics/operator:config-reloader-v0.38.0 | false | - |
| VM_CUSTOMCONFIGRELOADERIMAGE | victoriametrics/operator:config-reloader-v0.44.0 | false | - |
| VM_PSPAUTOCREATEENABLED | false | false | - |
| VM_VMALERTDEFAULT_IMAGE | victoriametrics/vmalert | false | - |
| VM_VMALERTDEFAULT_VERSION | v1.99.0 | false | - |
| VM_VMALERTDEFAULT_VERSION | v1.100.1 | false | - |
| VM_VMALERTDEFAULT_PORT | 8080 | false | - |
| VM_VMALERTDEFAULT_USEDEFAULTRESOURCES | true | false | - |
| VM_VMALERTDEFAULT_RESOURCE_LIMIT_MEM | 500Mi | false | - |
@@ -31,7 +31,7 @@ menu:
| VM_VMALERTDEFAULT_CONFIGRELOADERMEMORY | 25Mi | false | - |
| VM_VMALERTDEFAULT_CONFIGRELOADIMAGE | jimmidyson/configmap-reload:v0.3.0 | false | - |
| VM_VMAGENTDEFAULT_IMAGE | victoriametrics/vmagent | false | - |
| VM_VMAGENTDEFAULT_VERSION | v1.99.0 | false | - |
| VM_VMAGENTDEFAULT_VERSION | v1.100.1 | false | - |
| VM_VMAGENTDEFAULT_CONFIGRELOADIMAGE | quay.io/prometheus-operator/prometheus-config-reloader:v0.68.0 | false | - |
| VM_VMAGENTDEFAULT_PORT | 8429 | false | - |
| VM_VMAGENTDEFAULT_USEDEFAULTRESOURCES | true | false | - |
@@ -42,7 +42,7 @@ menu:
| VM_VMAGENTDEFAULT_CONFIGRELOADERCPU | 100m | false | - |
| VM_VMAGENTDEFAULT_CONFIGRELOADERMEMORY | 25Mi | false | - |
| VM_VMSINGLEDEFAULT_IMAGE | victoriametrics/victoria-metrics | false | - |
| VM_VMSINGLEDEFAULT_VERSION | v1.99.0 | false | - |
| VM_VMSINGLEDEFAULT_VERSION | v1.100.1 | false | - |
| VM_VMSINGLEDEFAULT_PORT | 8429 | false | - |
| VM_VMSINGLEDEFAULT_USEDEFAULTRESOURCES | true | false | - |
| VM_VMSINGLEDEFAULT_RESOURCE_LIMIT_MEM | 1500Mi | false | - |
@@ -53,14 +53,14 @@ menu:
| VM_VMSINGLEDEFAULT_CONFIGRELOADERMEMORY | 25Mi | false | - |
| VM_VMCLUSTERDEFAULT_USEDEFAULTRESOURCES | true | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_IMAGE | victoriametrics/vmselect | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_VERSION | v1.99.0-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_VERSION | v1.100.1-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_PORT | 8481 | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_RESOURCE_LIMIT_MEM | 1000Mi | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_RESOURCE_LIMIT_CPU | 500m | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_RESOURCE_REQUEST_MEM | 500Mi | false | - |
| VM_VMCLUSTERDEFAULT_VMSELECTDEFAULT_RESOURCE_REQUEST_CPU | 100m | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_IMAGE | victoriametrics/vmstorage | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_VERSION | v1.99.0-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_VERSION | v1.100.1-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_VMINSERTPORT | 8400 | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_VMSELECTPORT | 8401 | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_PORT | 8482 | false | - |
@@ -69,7 +69,7 @@ menu:
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_RESOURCE_REQUEST_MEM | 500Mi | false | - |
| VM_VMCLUSTERDEFAULT_VMSTORAGEDEFAULT_RESOURCE_REQUEST_CPU | 250m | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_IMAGE | victoriametrics/vminsert | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_VERSION | v1.99.0-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_VERSION | v1.100.1-cluster | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_PORT | 8480 | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_RESOURCE_LIMIT_MEM | 500Mi | false | - |
| VM_VMCLUSTERDEFAULT_VMINSERTDEFAULT_RESOURCE_LIMIT_CPU | 500m | false | - |
@@ -88,7 +88,7 @@ menu:
| VM_VMALERTMANAGER_RESOURCE_REQUEST_CPU | 30m | false | - |
| VM_DISABLESELFSERVICESCRAPECREATION | false | false | - |
| VM_VMBACKUP_IMAGE | victoriametrics/vmbackupmanager | false | - |
| VM_VMBACKUP_VERSION | v1.99.0-enterprise | false | - |
| VM_VMBACKUP_VERSION | v1.100.1-enterprise | false | - |
| VM_VMBACKUP_PORT | 8300 | false | - |
| VM_VMBACKUP_USEDEFAULTRESOURCES | true | false | - |
| VM_VMBACKUP_RESOURCE_LIMIT_MEM | 500Mi | false | - |
@@ -97,7 +97,7 @@ menu:
| VM_VMBACKUP_RESOURCE_REQUEST_CPU | 150m | false | - |
| VM_VMBACKUP_LOGLEVEL | INFO | false | - |
| VM_VMAUTHDEFAULT_IMAGE | victoriametrics/vmauth | false | - |
| VM_VMAUTHDEFAULT_VERSION | v1.99.0 | false | - |
| VM_VMAUTHDEFAULT_VERSION | v1.100.1 | false | - |
| VM_VMAUTHDEFAULT_CONFIGRELOADIMAGE | quay.io/prometheus-operator/prometheus-config-reloader:v0.68.0 | false | - |
| VM_VMAUTHDEFAULT_PORT | 8427 | false | - |
| VM_VMAUTHDEFAULT_USEDEFAULTRESOURCES | true | false | - |
@@ -112,6 +112,7 @@ menu:
| VM_ENABLEDPROMETHEUSCONVERTER_PROMETHEUSRULE | true | false | - |
| VM_ENABLEDPROMETHEUSCONVERTER_PROBE | true | false | - |
| VM_ENABLEDPROMETHEUSCONVERTER_ALERTMANAGERCONFIG | true | false | - |
| VM_ENABLEDPROMETHEUSCONVERTER_SCRAPECONFIG | true | false | - |
| VM_FILTERCHILDLABELPREFIXES | - | false | - |
| VM_FILTERCHILDANNOTATIONPREFIXES | - | false | - |
| VM_PROMETHEUSCONVERTERADDARGOCDIGNOREANNOTATIONS | false | false | adds compare-options and sync-options for prometheus objects converted by operatorit helps to properly use converter with ArgoCD |

View File

@@ -34,8 +34,8 @@ scrape_configs:
After you created the `scrape.yaml` file, download and unpack [single-node VictoriaMetrics](https://docs.victoriametrics.com/) to the same directory:
```
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.0/victoria-metrics-linux-amd64-v1.100.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.100.0.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.1/victoria-metrics-linux-amd64-v1.100.1.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.100.1.tar.gz
```
Then start VictoriaMetrics and instruct it to scrape targets defined in `scrape.yaml` and save scraped metrics
@@ -150,8 +150,8 @@ Then start [single-node VictoriaMetrics](https://docs.victoriametrics.com/) acco
```yaml
# Download and unpack single-node VictoriaMetrics
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.0/victoria-metrics-linux-amd64-v1.100.0.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.100.0.tar.gz
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.100.1/victoria-metrics-linux-amd64-v1.100.1.tar.gz
tar xzf victoria-metrics-linux-amd64-v1.100.1.tar.gz
# Run single-node VictoriaMetrics with the given scrape.yaml
./victoria-metrics-prod -promscrape.config=scrape.yaml

View File

@@ -1471,7 +1471,8 @@ func mustOpenParts(path string) []*partWrapper {
fs.MustRemoveAll(filepath.Join(path, "txn"))
fs.MustRemoveAll(filepath.Join(path, "tmp"))
partNames := mustReadPartNames(path)
partsFile := filepath.Join(path, partsFilename)
partNames := mustReadPartNames(partsFile, path)
// Remove dirs missing in partNames. These dirs may be left after unclean shutdown
// or after the update from versions prior to v1.90.0.
@@ -1484,7 +1485,6 @@ func mustOpenParts(path string) []*partWrapper {
// including unclean shutdown.
partPath := filepath.Join(path, partName)
if !fs.IsPathExist(partPath) {
partsFile := filepath.Join(path, partsFilename)
logger.Panicf("FATAL: part %q is listed in %q, but is missing on disk; "+
"ensure %q contents is not corrupted; remove %q to rebuild its' content from the list of existing parts",
partPath, partsFile, partsFile, partsFile)
@@ -1500,6 +1500,7 @@ func mustOpenParts(path string) []*partWrapper {
fn := de.Name()
if _, ok := m[fn]; !ok {
deletePath := filepath.Join(path, fn)
logger.Infof("deleting %q because it isn't listed in %q; this is the expected case after unclean shutdown", deletePath, partsFile)
fs.MustRemoveAll(deletePath)
}
}
@@ -1516,8 +1517,7 @@ func mustOpenParts(path string) []*partWrapper {
pw.incRef()
pws = append(pws, pw)
}
partNamesPath := filepath.Join(path, partsFilename)
if !fs.IsPathExist(partNamesPath) {
if !fs.IsPathExist(partsFile) {
// Create parts.json file if it doesn't exist yet.
// This should protect from possible carshloops just after the migration from versions below v1.90.0
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4336
@@ -1595,20 +1595,19 @@ func mustWritePartNames(pws []*partWrapper, dstDir string) {
if err != nil {
logger.Panicf("BUG: cannot marshal partNames to JSON: %s", err)
}
partNamesPath := filepath.Join(dstDir, partsFilename)
fs.MustWriteAtomic(partNamesPath, data, true)
partsFile := filepath.Join(dstDir, partsFilename)
fs.MustWriteAtomic(partsFile, data, true)
}
func mustReadPartNames(srcDir string) []string {
partNamesPath := filepath.Join(srcDir, partsFilename)
if fs.IsPathExist(partNamesPath) {
data, err := os.ReadFile(partNamesPath)
func mustReadPartNames(partsFile, srcDir string) []string {
if fs.IsPathExist(partsFile) {
data, err := os.ReadFile(partsFile)
if err != nil {
logger.Panicf("FATAL: cannot read %s file: %s", partsFilename, err)
logger.Panicf("FATAL: cannot read %q: %s", partsFile, err)
}
var partNames []string
if err := json.Unmarshal(data, &partNames); err != nil {
logger.Panicf("FATAL: cannot parse %s: %s", partNamesPath, err)
logger.Panicf("FATAL: cannot parse %q: %s", partsFile, err)
}
return partNames
}

View File

@@ -19,7 +19,7 @@ type SDConfig struct {
// Namespace only supported at enterprise consul.
// https://www.consul.io/docs/enterprise/namespaces
Namespace string `yaml:"namespace,omitempty"`
// Partition only supported at enteprise consul.
// Partition only supported at enterprise consul.
// https://developer.hashicorp.com/consul/docs/enterprise/admin-partitions
Partition string `yaml:"partition,omitempty"`

View File

@@ -509,22 +509,23 @@ func (is *indexSearch) createGlobalIndexes(tsid *TSID, mn *MetricName) {
ii := getIndexItems()
defer putIndexItems(ii)
// Create MetricID -> MetricName index.
// Create metricID -> metricName entry.
ii.B = marshalCommonPrefix(ii.B, nsPrefixMetricIDToMetricName)
ii.B = encoding.MarshalUint64(ii.B, tsid.MetricID)
ii.B = mn.Marshal(ii.B)
ii.Next()
// Create MetricID -> TSID index.
// Create metricID -> TSID entry.
ii.B = marshalCommonPrefix(ii.B, nsPrefixMetricIDToTSID)
ii.B = encoding.MarshalUint64(ii.B, tsid.MetricID)
ii.B = tsid.Marshal(ii.B)
ii.Next()
prefix := kbPool.Get()
prefix.B = marshalCommonPrefix(prefix.B[:0], nsPrefixTagToMetricIDs)
ii.registerTagIndexes(prefix.B, mn, tsid.MetricID)
kbPool.Put(prefix)
// Create tag -> metricID entries for every tag in mn.
kb := kbPool.Get()
kb.B = marshalCommonPrefix(kb.B[:0], nsPrefixTagToMetricIDs)
ii.registerTagIndexes(kb.B, mn, tsid.MetricID)
kbPool.Put(kb)
is.db.tb.AddItems(ii.Items)
}
@@ -2717,12 +2718,13 @@ func (is *indexSearch) createPerDayIndexes(date uint64, tsid *TSID, mn *MetricNa
ii := getIndexItems()
defer putIndexItems(ii)
// Create date -> metricID entry.
ii.B = marshalCommonPrefix(ii.B, nsPrefixDateToMetricID)
ii.B = encoding.MarshalUint64(ii.B, date)
ii.B = encoding.MarshalUint64(ii.B, tsid.MetricID)
ii.Next()
// Create per-day inverted index entries for TSID.
// Create metricName -> TSID entry.
ii.B = marshalCommonPrefix(ii.B, nsPrefixDateMetricNameToTSID)
ii.B = encoding.MarshalUint64(ii.B, date)
ii.B = mn.Marshal(ii.B)
@@ -2730,17 +2732,18 @@ func (is *indexSearch) createPerDayIndexes(date uint64, tsid *TSID, mn *MetricNa
ii.B = tsid.Marshal(ii.B)
ii.Next()
// Create per-day inverted index entries for metricID.
// Create per-day tag -> metricID entries for every tag in mn.
kb := kbPool.Get()
defer kbPool.Put(kb)
kb.B = marshalCommonPrefix(kb.B[:0], nsPrefixDateTagToMetricIDs)
kb.B = encoding.MarshalUint64(kb.B, date)
ii.registerTagIndexes(kb.B, mn, tsid.MetricID)
kbPool.Put(kb)
is.db.tb.AddItems(ii.Items)
}
func (ii *indexItems) registerTagIndexes(prefix []byte, mn *MetricName, metricID uint64) {
// Add index entry for MetricGroup -> MetricID
// Add MetricGroup -> metricID entry.
ii.B = append(ii.B, prefix...)
ii.B = marshalTagValue(ii.B, nil)
ii.B = marshalTagValue(ii.B, mn.MetricGroup)
@@ -2748,7 +2751,7 @@ func (ii *indexItems) registerTagIndexes(prefix []byte, mn *MetricName, metricID
ii.Next()
ii.addReverseMetricGroupIfNeeded(prefix, mn, metricID)
// Add index entries for tags: tag -> MetricID
// Add tag -> metricID entries.
for _, tag := range mn.Tags {
ii.B = append(ii.B, prefix...)
ii.B = tag.Marshal(ii.B)
@@ -2756,7 +2759,7 @@ func (ii *indexItems) registerTagIndexes(prefix []byte, mn *MetricName, metricID
ii.Next()
}
// Add index entries for composite tags: MetricGroup+tag -> MetricID
// Add index entries for composite tags: MetricGroup+tag -> metricID.
compositeKey := kbPool.Get()
for _, tag := range mn.Tags {
compositeKey.B = marshalCompositeTagKey(compositeKey.B[:0], mn.MetricGroup, tag.Key)

View File

@@ -246,13 +246,13 @@ func mustOpenPartition(smallPartsPath, bigPartsPath string, s *Storage) *partiti
logger.Panicf("FATAL: partition name in bigPartsPath %q doesn't match smallPartsPath %q; want %q", bigPartsPath, smallPartsPath, name)
}
partNamesSmall, partNamesBig := mustReadPartNames(smallPartsPath, bigPartsPath)
partsFile := filepath.Join(smallPartsPath, partsFilename)
partNamesSmall, partNamesBig := mustReadPartNames(partsFile, smallPartsPath, bigPartsPath)
smallParts := mustOpenParts(smallPartsPath, partNamesSmall)
bigParts := mustOpenParts(bigPartsPath, partNamesBig)
smallParts := mustOpenParts(partsFile, smallPartsPath, partNamesSmall)
bigParts := mustOpenParts(partsFile, bigPartsPath, partNamesBig)
partNamesPath := filepath.Join(smallPartsPath, partsFilename)
if !fs.IsPathExist(partNamesPath) {
if !fs.IsPathExist(partsFile) {
// Create parts.json file if it doesn't exist yet.
// This should protect from possible carshloops just after the migration from versions below v1.90.0
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4336
@@ -1905,7 +1905,7 @@ func getPartsSize(pws []*partWrapper) uint64 {
return n
}
func mustOpenParts(path string, partNames []string) []*partWrapper {
func mustOpenParts(partsFile, path string, partNames []string) []*partWrapper {
// The path can be missing after restoring from backup, so create it if needed.
fs.MustMkdirIfNotExist(path)
fs.MustRemoveTemporaryDirs(path)
@@ -1926,7 +1926,6 @@ func mustOpenParts(path string, partNames []string) []*partWrapper {
// including unclean shutdown.
partPath := filepath.Join(path, partName)
if !fs.IsPathExist(partPath) {
partsFile := filepath.Join(path, partsFilename)
logger.Panicf("FATAL: part %q is listed in %q, but is missing on disk; "+
"ensure %q contents is not corrupted; remove %q to rebuild its' content from the list of existing parts",
partPath, partsFile, partsFile, partsFile)
@@ -1942,6 +1941,7 @@ func mustOpenParts(path string, partNames []string) []*partWrapper {
fn := de.Name()
if _, ok := m[fn]; !ok {
deletePath := filepath.Join(path, fn)
logger.Infof("deleting %q because it isn't listed in %q; this is the expected case after unclean shutdown", deletePath, partsFile)
fs.MustRemoveAll(deletePath)
}
}
@@ -2037,8 +2037,8 @@ func mustWritePartNames(pwsSmall, pwsBig []*partWrapper, dstDir string) {
if err != nil {
logger.Panicf("BUG: cannot marshal partNames to JSON: %s", err)
}
partNamesPath := filepath.Join(dstDir, partsFilename)
fs.MustWriteAtomic(partNamesPath, data, true)
partsFile := filepath.Join(dstDir, partsFilename)
fs.MustWriteAtomic(partsFile, data, true)
}
func getPartNames(pws []*partWrapper) []string {
@@ -2055,20 +2055,19 @@ func getPartNames(pws []*partWrapper) []string {
return partNames
}
func mustReadPartNames(smallPartsPath, bigPartsPath string) ([]string, []string) {
partNamesPath := filepath.Join(smallPartsPath, partsFilename)
if fs.IsPathExist(partNamesPath) {
data, err := os.ReadFile(partNamesPath)
func mustReadPartNames(partsFile, smallPartsPath, bigPartsPath string) ([]string, []string) {
if fs.IsPathExist(partsFile) {
data, err := os.ReadFile(partsFile)
if err != nil {
logger.Panicf("FATAL: cannot read %s file: %s", partsFilename, err)
logger.Panicf("FATAL: cannot read %q: %s", partsFile, err)
}
var partNames partNamesJSON
if err := json.Unmarshal(data, &partNames); err != nil {
logger.Panicf("FATAL: cannot parse %s: %s", partNamesPath, err)
logger.Panicf("FATAL: cannot parse %q: %s", partsFile, err)
}
return partNames.Small, partNames.Big
}
// The partsFilename is missing. This is the upgrade from versions previous to v1.90.0.
// The partsFile is missing. This is the upgrade from versions previous to v1.90.0.
// Read part names from smallPartsPath and bigPartsPath directories
partNamesSmall := mustReadPartNamesFromDir(smallPartsPath)
partNamesBig := mustReadPartNamesFromDir(bigPartsPath)