mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-14 06:15:45 +00:00
Merge pull request #126984 from dashpole/fix_mem_leak_30
Cherrypick of #126957 on 1.30: Fix memory leak from global OpenTelemetry MeterProvider
This commit is contained in:
commit
a184d0fdeb
@ -38,6 +38,8 @@ import (
|
|||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/metric/noop"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
@ -120,6 +122,9 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
|
utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
|
||||||
|
// Prevent memory leak from OTel metrics, which we don't use:
|
||||||
|
// https://github.com/open-telemetry/opentelemetry-go-contrib/issues/5190
|
||||||
|
otel.SetMeterProvider(noop.NewMeterProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
2
go.mod
2
go.mod
@ -68,6 +68,7 @@ require (
|
|||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0
|
||||||
go.opentelemetry.io/otel v1.19.0
|
go.opentelemetry.io/otel v1.19.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
|
||||||
|
go.opentelemetry.io/otel/metric v1.19.0
|
||||||
go.opentelemetry.io/otel/sdk v1.19.0
|
go.opentelemetry.io/otel/sdk v1.19.0
|
||||||
go.opentelemetry.io/otel/trace v1.19.0
|
go.opentelemetry.io/otel/trace v1.19.0
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0
|
go.opentelemetry.io/proto/otlp v1.0.0
|
||||||
@ -215,7 +216,6 @@ require (
|
|||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
|
@ -30,6 +30,7 @@ require (
|
|||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0
|
||||||
go.opentelemetry.io/otel v1.19.0
|
go.opentelemetry.io/otel v1.19.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
|
||||||
|
go.opentelemetry.io/otel/metric v1.19.0
|
||||||
go.opentelemetry.io/otel/sdk v1.19.0
|
go.opentelemetry.io/otel/sdk v1.19.0
|
||||||
go.opentelemetry.io/otel/trace v1.19.0
|
go.opentelemetry.io/otel/trace v1.19.0
|
||||||
go.uber.org/zap v1.26.0
|
go.uber.org/zap v1.26.0
|
||||||
@ -109,7 +110,6 @@ require (
|
|||||||
go.etcd.io/etcd/pkg/v3 v3.5.10 // indirect
|
go.etcd.io/etcd/pkg/v3 v3.5.10 // indirect
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.10 // indirect
|
go.etcd.io/etcd/raft/v3 v3.5.10 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
|
@ -23,7 +23,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||||
|
"go.opentelemetry.io/otel/metric/noop"
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
"go.opentelemetry.io/otel/semconv/v1.12.0"
|
"go.opentelemetry.io/otel/semconv/v1.12.0"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@ -48,6 +50,12 @@ var (
|
|||||||
codecs = serializer.NewCodecFactory(cfgScheme)
|
codecs = serializer.NewCodecFactory(cfgScheme)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Prevent memory leak from OTel metrics, which we don't use:
|
||||||
|
// https://github.com/open-telemetry/opentelemetry-go-contrib/issues/5190
|
||||||
|
otel.SetMeterProvider(noop.NewMeterProvider())
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
install.Install(cfgScheme)
|
install.Install(cfgScheme)
|
||||||
}
|
}
|
||||||
|
264
vendor/go.opentelemetry.io/otel/metric/noop/noop.go
generated
vendored
Normal file
264
vendor/go.opentelemetry.io/otel/metric/noop/noop.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package noop provides an implementation of the OpenTelemetry metric API that
|
||||||
|
// produces no telemetry and minimizes used computation resources.
|
||||||
|
//
|
||||||
|
// Using this package to implement the OpenTelemetry metric API will
|
||||||
|
// effectively disable OpenTelemetry.
|
||||||
|
//
|
||||||
|
// This implementation can be embedded in other implementations of the
|
||||||
|
// OpenTelemetry metric API. Doing so will mean the implementation defaults to
|
||||||
|
// no operation for methods it does not implement.
|
||||||
|
package noop // import "go.opentelemetry.io/otel/metric/noop"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
"go.opentelemetry.io/otel/metric/embedded"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Compile-time check this implements the OpenTelemetry API.
|
||||||
|
|
||||||
|
_ metric.MeterProvider = MeterProvider{}
|
||||||
|
_ metric.Meter = Meter{}
|
||||||
|
_ metric.Observer = Observer{}
|
||||||
|
_ metric.Registration = Registration{}
|
||||||
|
_ metric.Int64Counter = Int64Counter{}
|
||||||
|
_ metric.Float64Counter = Float64Counter{}
|
||||||
|
_ metric.Int64UpDownCounter = Int64UpDownCounter{}
|
||||||
|
_ metric.Float64UpDownCounter = Float64UpDownCounter{}
|
||||||
|
_ metric.Int64Histogram = Int64Histogram{}
|
||||||
|
_ metric.Float64Histogram = Float64Histogram{}
|
||||||
|
_ metric.Int64ObservableCounter = Int64ObservableCounter{}
|
||||||
|
_ metric.Float64ObservableCounter = Float64ObservableCounter{}
|
||||||
|
_ metric.Int64ObservableGauge = Int64ObservableGauge{}
|
||||||
|
_ metric.Float64ObservableGauge = Float64ObservableGauge{}
|
||||||
|
_ metric.Int64ObservableUpDownCounter = Int64ObservableUpDownCounter{}
|
||||||
|
_ metric.Float64ObservableUpDownCounter = Float64ObservableUpDownCounter{}
|
||||||
|
_ metric.Int64Observer = Int64Observer{}
|
||||||
|
_ metric.Float64Observer = Float64Observer{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// MeterProvider is an OpenTelemetry No-Op MeterProvider.
|
||||||
|
type MeterProvider struct{ embedded.MeterProvider }
|
||||||
|
|
||||||
|
// NewMeterProvider returns a MeterProvider that does not record any telemetry.
|
||||||
|
func NewMeterProvider() MeterProvider {
|
||||||
|
return MeterProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter returns an OpenTelemetry Meter that does not record any telemetry.
|
||||||
|
func (MeterProvider) Meter(string, ...metric.MeterOption) metric.Meter {
|
||||||
|
return Meter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter is an OpenTelemetry No-Op Meter.
|
||||||
|
type Meter struct{ embedded.Meter }
|
||||||
|
|
||||||
|
// Int64Counter returns a Counter used to record int64 measurements that
|
||||||
|
// produces no telemetry.
|
||||||
|
func (Meter) Int64Counter(string, ...metric.Int64CounterOption) (metric.Int64Counter, error) {
|
||||||
|
return Int64Counter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64UpDownCounter returns an UpDownCounter used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Int64UpDownCounter(string, ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) {
|
||||||
|
return Int64UpDownCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Histogram returns a Histogram used to record int64 measurements that
|
||||||
|
// produces no telemetry.
|
||||||
|
func (Meter) Int64Histogram(string, ...metric.Int64HistogramOption) (metric.Int64Histogram, error) {
|
||||||
|
return Int64Histogram{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ObservableCounter returns an ObservableCounter used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Int64ObservableCounter(string, ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
|
||||||
|
return Int64ObservableCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ObservableUpDownCounter returns an ObservableUpDownCounter used to
|
||||||
|
// record int64 measurements that produces no telemetry.
|
||||||
|
func (Meter) Int64ObservableUpDownCounter(string, ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
|
||||||
|
return Int64ObservableUpDownCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ObservableGauge returns an ObservableGauge used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Int64ObservableGauge(string, ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) {
|
||||||
|
return Int64ObservableGauge{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Counter returns a Counter used to record int64 measurements that
|
||||||
|
// produces no telemetry.
|
||||||
|
func (Meter) Float64Counter(string, ...metric.Float64CounterOption) (metric.Float64Counter, error) {
|
||||||
|
return Float64Counter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64UpDownCounter returns an UpDownCounter used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Float64UpDownCounter(string, ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) {
|
||||||
|
return Float64UpDownCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Histogram returns a Histogram used to record int64 measurements that
|
||||||
|
// produces no telemetry.
|
||||||
|
func (Meter) Float64Histogram(string, ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
|
||||||
|
return Float64Histogram{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableCounter returns an ObservableCounter used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Float64ObservableCounter(string, ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
|
||||||
|
return Float64ObservableCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableUpDownCounter returns an ObservableUpDownCounter used to
|
||||||
|
// record int64 measurements that produces no telemetry.
|
||||||
|
func (Meter) Float64ObservableUpDownCounter(string, ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
|
||||||
|
return Float64ObservableUpDownCounter{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableGauge returns an ObservableGauge used to record int64
|
||||||
|
// measurements that produces no telemetry.
|
||||||
|
func (Meter) Float64ObservableGauge(string, ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
|
||||||
|
return Float64ObservableGauge{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCallback performs no operation.
|
||||||
|
func (Meter) RegisterCallback(metric.Callback, ...metric.Observable) (metric.Registration, error) {
|
||||||
|
return Registration{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observer acts as a recorder of measurements for multiple instruments in a
|
||||||
|
// Callback, it performing no operation.
|
||||||
|
type Observer struct{ embedded.Observer }
|
||||||
|
|
||||||
|
// ObserveFloat64 performs no operation.
|
||||||
|
func (Observer) ObserveFloat64(metric.Float64Observable, float64, ...metric.ObserveOption) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObserveInt64 performs no operation.
|
||||||
|
func (Observer) ObserveInt64(metric.Int64Observable, int64, ...metric.ObserveOption) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registration is the registration of a Callback with a No-Op Meter.
|
||||||
|
type Registration struct{ embedded.Registration }
|
||||||
|
|
||||||
|
// Unregister unregisters the Callback the Registration represents with the
|
||||||
|
// No-Op Meter. This will always return nil because the No-Op Meter performs no
|
||||||
|
// operation, including hold any record of registrations.
|
||||||
|
func (Registration) Unregister() error { return nil }
|
||||||
|
|
||||||
|
// Int64Counter is an OpenTelemetry Counter used to record int64 measurements.
|
||||||
|
// It produces no telemetry.
|
||||||
|
type Int64Counter struct{ embedded.Int64Counter }
|
||||||
|
|
||||||
|
// Add performs no operation.
|
||||||
|
func (Int64Counter) Add(context.Context, int64, ...metric.AddOption) {}
|
||||||
|
|
||||||
|
// Float64Counter is an OpenTelemetry Counter used to record float64
|
||||||
|
// measurements. It produces no telemetry.
|
||||||
|
type Float64Counter struct{ embedded.Float64Counter }
|
||||||
|
|
||||||
|
// Add performs no operation.
|
||||||
|
func (Float64Counter) Add(context.Context, float64, ...metric.AddOption) {}
|
||||||
|
|
||||||
|
// Int64UpDownCounter is an OpenTelemetry UpDownCounter used to record int64
|
||||||
|
// measurements. It produces no telemetry.
|
||||||
|
type Int64UpDownCounter struct{ embedded.Int64UpDownCounter }
|
||||||
|
|
||||||
|
// Add performs no operation.
|
||||||
|
func (Int64UpDownCounter) Add(context.Context, int64, ...metric.AddOption) {}
|
||||||
|
|
||||||
|
// Float64UpDownCounter is an OpenTelemetry UpDownCounter used to record
|
||||||
|
// float64 measurements. It produces no telemetry.
|
||||||
|
type Float64UpDownCounter struct{ embedded.Float64UpDownCounter }
|
||||||
|
|
||||||
|
// Add performs no operation.
|
||||||
|
func (Float64UpDownCounter) Add(context.Context, float64, ...metric.AddOption) {}
|
||||||
|
|
||||||
|
// Int64Histogram is an OpenTelemetry Histogram used to record int64
|
||||||
|
// measurements. It produces no telemetry.
|
||||||
|
type Int64Histogram struct{ embedded.Int64Histogram }
|
||||||
|
|
||||||
|
// Record performs no operation.
|
||||||
|
func (Int64Histogram) Record(context.Context, int64, ...metric.RecordOption) {}
|
||||||
|
|
||||||
|
// Float64Histogram is an OpenTelemetry Histogram used to record float64
|
||||||
|
// measurements. It produces no telemetry.
|
||||||
|
type Float64Histogram struct{ embedded.Float64Histogram }
|
||||||
|
|
||||||
|
// Record performs no operation.
|
||||||
|
func (Float64Histogram) Record(context.Context, float64, ...metric.RecordOption) {}
|
||||||
|
|
||||||
|
// Int64ObservableCounter is an OpenTelemetry ObservableCounter used to record
|
||||||
|
// int64 measurements. It produces no telemetry.
|
||||||
|
type Int64ObservableCounter struct {
|
||||||
|
metric.Int64Observable
|
||||||
|
embedded.Int64ObservableCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableCounter is an OpenTelemetry ObservableCounter used to record
|
||||||
|
// float64 measurements. It produces no telemetry.
|
||||||
|
type Float64ObservableCounter struct {
|
||||||
|
metric.Float64Observable
|
||||||
|
embedded.Float64ObservableCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ObservableGauge is an OpenTelemetry ObservableGauge used to record
|
||||||
|
// int64 measurements. It produces no telemetry.
|
||||||
|
type Int64ObservableGauge struct {
|
||||||
|
metric.Int64Observable
|
||||||
|
embedded.Int64ObservableGauge
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableGauge is an OpenTelemetry ObservableGauge used to record
|
||||||
|
// float64 measurements. It produces no telemetry.
|
||||||
|
type Float64ObservableGauge struct {
|
||||||
|
metric.Float64Observable
|
||||||
|
embedded.Float64ObservableGauge
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ObservableUpDownCounter is an OpenTelemetry ObservableUpDownCounter
|
||||||
|
// used to record int64 measurements. It produces no telemetry.
|
||||||
|
type Int64ObservableUpDownCounter struct {
|
||||||
|
metric.Int64Observable
|
||||||
|
embedded.Int64ObservableUpDownCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ObservableUpDownCounter is an OpenTelemetry ObservableUpDownCounter
|
||||||
|
// used to record float64 measurements. It produces no telemetry.
|
||||||
|
type Float64ObservableUpDownCounter struct {
|
||||||
|
metric.Float64Observable
|
||||||
|
embedded.Float64ObservableUpDownCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Observer is a recorder of int64 measurements that performs no operation.
|
||||||
|
type Int64Observer struct{ embedded.Int64Observer }
|
||||||
|
|
||||||
|
// Observe performs no operation.
|
||||||
|
func (Int64Observer) Observe(int64, ...metric.ObserveOption) {}
|
||||||
|
|
||||||
|
// Float64Observer is a recorder of float64 measurements that performs no
|
||||||
|
// operation.
|
||||||
|
type Float64Observer struct{ embedded.Float64Observer }
|
||||||
|
|
||||||
|
// Observe performs no operation.
|
||||||
|
func (Float64Observer) Observe(float64, ...metric.ObserveOption) {}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -837,6 +837,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry
|
|||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
go.opentelemetry.io/otel/metric
|
go.opentelemetry.io/otel/metric
|
||||||
go.opentelemetry.io/otel/metric/embedded
|
go.opentelemetry.io/otel/metric/embedded
|
||||||
|
go.opentelemetry.io/otel/metric/noop
|
||||||
# go.opentelemetry.io/otel/sdk v1.19.0
|
# go.opentelemetry.io/otel/sdk v1.19.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
go.opentelemetry.io/otel/sdk
|
go.opentelemetry.io/otel/sdk
|
||||||
|
Loading…
Reference in New Issue
Block a user