mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore] Add Go runtime and host metrics (#4137)
Daenney is a dummy and forgot to add these when he revamped the OTEL stuff. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4137 Co-authored-by: Daenney <daenney@noreply.codeberg.org> Co-committed-by: Daenney <daenney@noreply.codeberg.org>
This commit is contained in:
1
go.mod
1
go.mod
@@ -73,6 +73,7 @@ require (
|
|||||||
github.com/wagslane/go-password-validator v0.3.0
|
github.com/wagslane/go-password-validator v0.3.0
|
||||||
github.com/yuin/goldmark v1.7.11
|
github.com/yuin/goldmark v1.7.11
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0
|
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime v0.60.0
|
||||||
go.opentelemetry.io/otel v1.35.0
|
go.opentelemetry.io/otel v1.35.0
|
||||||
go.opentelemetry.io/otel/metric v1.35.0
|
go.opentelemetry.io/otel/metric v1.35.0
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0
|
go.opentelemetry.io/otel/sdk v1.35.0
|
||||||
|
2
go.sum
generated
2
go.sum
generated
@@ -495,6 +495,8 @@ go.opentelemetry.io/contrib/bridges/prometheus v0.60.0 h1:x7sPooQCwSg27SjtQee8Gy
|
|||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0/go.mod h1:4K5UXgiHxV484efGs42ejD7E2J/sIlepYgdGoPXe7hE=
|
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0/go.mod h1:4K5UXgiHxV484efGs42ejD7E2J/sIlepYgdGoPXe7hE=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 h1:GuQXpvSXNjpswpweIem84U9BNauqHHi2w1GtNAalvpM=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 h1:GuQXpvSXNjpswpweIem84U9BNauqHHi2w1GtNAalvpM=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0/go.mod h1:CkmxekdHco4d7thFJNPQ7Mby4jMBgZUclnrxT4e+ryk=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0/go.mod h1:CkmxekdHco4d7thFJNPQ7Mby4jMBgZUclnrxT4e+ryk=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime v0.60.0 h1:0NgN/3SYkqYJ9NBlDfl/2lzVlwos/YQLvi8sUrzJRBE=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime v0.60.0/go.mod h1:oxpUfhTkhgQaYIjtBt3T3w135dLoxq//qo3WPlPIKkE=
|
||||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 h1:HMUytBT3uGhPKYY/u/G5MR9itrlSO2SMOsSD3Tk3k7A=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 h1:HMUytBT3uGhPKYY/u/G5MR9itrlSO2SMOsSD3Tk3k7A=
|
||||||
|
@@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/technologize/otel-go-contrib/otelginmetrics"
|
"github.com/technologize/otel-go-contrib/otelginmetrics"
|
||||||
"go.opentelemetry.io/contrib/exporters/autoexport"
|
"go.opentelemetry.io/contrib/exporters/autoexport"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/metric"
|
"go.opentelemetry.io/otel/metric"
|
||||||
sdk "go.opentelemetry.io/otel/sdk/metric"
|
sdk "go.opentelemetry.io/otel/sdk/metric"
|
||||||
@@ -59,6 +60,12 @@ func InitializeMetrics(ctx context.Context, db db.DB) error {
|
|||||||
|
|
||||||
otel.SetMeterProvider(meterProvider)
|
otel.SetMeterProvider(meterProvider)
|
||||||
|
|
||||||
|
if err := runtime.Start(
|
||||||
|
runtime.WithMeterProvider(meterProvider),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
meter := meterProvider.Meter(serviceName)
|
meter := meterProvider.Meter(serviceName)
|
||||||
|
|
||||||
thisInstance := config.GetHost()
|
thisInstance := config.GetHost()
|
||||||
|
201
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/LICENSE
generated
vendored
Normal file
201
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
34
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/doc.go
generated
vendored
Normal file
34
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/doc.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package runtime implements the conventional runtime metrics specified by OpenTelemetry.
|
||||||
|
//
|
||||||
|
// The metric events produced are:
|
||||||
|
//
|
||||||
|
// runtime.go.cgo.calls - Number of cgo calls made by the current process
|
||||||
|
// runtime.go.gc.count - Number of completed garbage collection cycles
|
||||||
|
// runtime.go.gc.pause_ns (ns) Amount of nanoseconds in GC stop-the-world pauses
|
||||||
|
// runtime.go.gc.pause_total_ns (ns) Cumulative nanoseconds in GC stop-the-world pauses since the program started
|
||||||
|
// runtime.go.goroutines - Number of goroutines that currently exist
|
||||||
|
// runtime.go.lookups - Number of pointer lookups performed by the runtime
|
||||||
|
// runtime.go.mem.heap_alloc (bytes) Bytes of allocated heap objects
|
||||||
|
// runtime.go.mem.heap_idle (bytes) Bytes in idle (unused) spans
|
||||||
|
// runtime.go.mem.heap_inuse (bytes) Bytes in in-use spans
|
||||||
|
// runtime.go.mem.heap_objects - Number of allocated heap objects
|
||||||
|
// runtime.go.mem.heap_released (bytes) Bytes of idle spans whose physical memory has been returned to the OS
|
||||||
|
// runtime.go.mem.heap_sys (bytes) Bytes of heap memory obtained from the OS
|
||||||
|
// runtime.go.mem.live_objects - Number of live objects is the number of cumulative Mallocs - Frees
|
||||||
|
// runtime.uptime (ms) Milliseconds since application was initialized
|
||||||
|
//
|
||||||
|
// When the OTEL_GO_X_DEPRECATED_RUNTIME_METRICS environment variable is set to
|
||||||
|
// false, the metrics produced are:
|
||||||
|
//
|
||||||
|
// go.memory.used By Memory used by the Go runtime.
|
||||||
|
// go.memory.limit By Go runtime memory limit configured by the user, if a limit exists.
|
||||||
|
// go.memory.allocated By Memory allocated to the heap by the application.
|
||||||
|
// go.memory.allocations {allocation} Count of allocations to the heap by the application.
|
||||||
|
// go.memory.gc.goal By Heap size target for the end of the GC cycle.
|
||||||
|
// go.goroutine.count {goroutine} Count of live goroutines.
|
||||||
|
// go.processor.limit {thread} The number of OS threads that can execute user-level Go code simultaneously.
|
||||||
|
// go.config.gogc % Heap size target percentage configured by the user, otherwise 100.
|
||||||
|
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
|
22
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime/doc.go
generated
vendored
Normal file
22
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime/doc.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package deprecatedruntime implements the deprecated runtime metrics for OpenTelemetry.
|
||||||
|
//
|
||||||
|
// The metric events produced are:
|
||||||
|
//
|
||||||
|
// runtime.go.cgo.calls - Number of cgo calls made by the current process
|
||||||
|
// runtime.go.gc.count - Number of completed garbage collection cycles
|
||||||
|
// runtime.go.gc.pause_ns (ns) Amount of nanoseconds in GC stop-the-world pauses
|
||||||
|
// runtime.go.gc.pause_total_ns (ns) Cumulative nanoseconds in GC stop-the-world pauses since the program started
|
||||||
|
// runtime.go.goroutines - Number of goroutines that currently exist
|
||||||
|
// runtime.go.lookups - Number of pointer lookups performed by the runtime
|
||||||
|
// runtime.go.mem.heap_alloc (bytes) Bytes of allocated heap objects
|
||||||
|
// runtime.go.mem.heap_idle (bytes) Bytes in idle (unused) spans
|
||||||
|
// runtime.go.mem.heap_inuse (bytes) Bytes in in-use spans
|
||||||
|
// runtime.go.mem.heap_objects - Number of allocated heap objects
|
||||||
|
// runtime.go.mem.heap_released (bytes) Bytes of idle spans whose physical memory has been returned to the OS
|
||||||
|
// runtime.go.mem.heap_sys (bytes) Bytes of heap memory obtained from the OS
|
||||||
|
// runtime.go.mem.live_objects - Number of live objects is the number of cumulative Mallocs - Frees
|
||||||
|
// runtime.uptime (ms) Milliseconds since application was initialized
|
||||||
|
package deprecatedruntime // import "go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
|
296
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime/runtime.go
generated
vendored
Normal file
296
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package deprecatedruntime // import "go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
goruntime "runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Runtime reports the work-in-progress conventional runtime metrics specified by OpenTelemetry.
|
||||||
|
type runtime struct {
|
||||||
|
minimumReadMemStatsInterval time.Duration
|
||||||
|
meter metric.Meter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start initializes reporting of runtime metrics using the supplied config.
|
||||||
|
func Start(meter metric.Meter, minimumReadMemStatsInterval time.Duration) error {
|
||||||
|
r := &runtime{
|
||||||
|
meter: meter,
|
||||||
|
minimumReadMemStatsInterval: minimumReadMemStatsInterval,
|
||||||
|
}
|
||||||
|
return r.register()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *runtime) register() error {
|
||||||
|
startTime := time.Now()
|
||||||
|
uptime, err := r.meter.Int64ObservableCounter(
|
||||||
|
"runtime.uptime",
|
||||||
|
metric.WithUnit("ms"),
|
||||||
|
metric.WithDescription("Milliseconds since application was initialized"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
goroutines, err := r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.goroutines",
|
||||||
|
metric.WithDescription("Number of goroutines that currently exist"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cgoCalls, err := r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.cgo.calls",
|
||||||
|
metric.WithDescription("Number of cgo calls made by the current process"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.meter.RegisterCallback(
|
||||||
|
func(ctx context.Context, o metric.Observer) error {
|
||||||
|
o.ObserveInt64(uptime, time.Since(startTime).Milliseconds())
|
||||||
|
o.ObserveInt64(goroutines, int64(goruntime.NumGoroutine()))
|
||||||
|
o.ObserveInt64(cgoCalls, goruntime.NumCgoCall())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
uptime,
|
||||||
|
goroutines,
|
||||||
|
cgoCalls,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.registerMemStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *runtime) registerMemStats() error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
|
||||||
|
heapAlloc metric.Int64ObservableUpDownCounter
|
||||||
|
heapIdle metric.Int64ObservableUpDownCounter
|
||||||
|
heapInuse metric.Int64ObservableUpDownCounter
|
||||||
|
heapObjects metric.Int64ObservableUpDownCounter
|
||||||
|
heapReleased metric.Int64ObservableUpDownCounter
|
||||||
|
heapSys metric.Int64ObservableUpDownCounter
|
||||||
|
liveObjects metric.Int64ObservableUpDownCounter
|
||||||
|
|
||||||
|
// TODO: is ptrLookups useful? I've not seen a value
|
||||||
|
// other than zero.
|
||||||
|
ptrLookups metric.Int64ObservableCounter
|
||||||
|
|
||||||
|
gcCount metric.Int64ObservableCounter
|
||||||
|
pauseTotalNs metric.Int64ObservableCounter
|
||||||
|
gcPauseNs metric.Int64Histogram
|
||||||
|
|
||||||
|
lastNumGC uint32
|
||||||
|
lastMemStats time.Time
|
||||||
|
memStats goruntime.MemStats
|
||||||
|
|
||||||
|
// lock prevents a race between batch observer and instrument registration.
|
||||||
|
lock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
if heapAlloc, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_alloc",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Bytes of allocated heap objects"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if heapIdle, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_idle",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Bytes in idle (unused) spans"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if heapInuse, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_inuse",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Bytes in in-use spans"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if heapObjects, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_objects",
|
||||||
|
metric.WithDescription("Number of allocated heap objects"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FYI see https://github.com/golang/go/issues/32284 to help
|
||||||
|
// understand the meaning of this value.
|
||||||
|
if heapReleased, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_released",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Bytes of idle spans whose physical memory has been returned to the OS"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if heapSys, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.heap_sys",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Bytes of heap memory obtained from the OS"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ptrLookups, err = r.meter.Int64ObservableCounter(
|
||||||
|
"process.runtime.go.mem.lookups",
|
||||||
|
metric.WithDescription("Number of pointer lookups performed by the runtime"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if liveObjects, err = r.meter.Int64ObservableUpDownCounter(
|
||||||
|
"process.runtime.go.mem.live_objects",
|
||||||
|
metric.WithDescription("Number of live objects is the number of cumulative Mallocs - Frees"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gcCount, err = r.meter.Int64ObservableCounter(
|
||||||
|
"process.runtime.go.gc.count",
|
||||||
|
metric.WithDescription("Number of completed garbage collection cycles"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the following could be derived as a sum of
|
||||||
|
// individual pauses, but we may lose individual pauses if the
|
||||||
|
// observation interval is too slow.
|
||||||
|
if pauseTotalNs, err = r.meter.Int64ObservableCounter(
|
||||||
|
"process.runtime.go.gc.pause_total_ns",
|
||||||
|
// TODO: nanoseconds units
|
||||||
|
metric.WithDescription("Cumulative nanoseconds in GC stop-the-world pauses since the program started"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gcPauseNs, err = r.meter.Int64Histogram(
|
||||||
|
"process.runtime.go.gc.pause_ns",
|
||||||
|
// TODO: nanoseconds units
|
||||||
|
metric.WithDescription("Amount of nanoseconds in GC stop-the-world pauses"),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.meter.RegisterCallback(
|
||||||
|
func(ctx context.Context, o metric.Observer) error {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if now.Sub(lastMemStats) >= r.minimumReadMemStatsInterval {
|
||||||
|
goruntime.ReadMemStats(&memStats)
|
||||||
|
lastMemStats = now
|
||||||
|
}
|
||||||
|
|
||||||
|
o.ObserveInt64(heapAlloc, clampUint64(memStats.HeapAlloc))
|
||||||
|
o.ObserveInt64(heapIdle, clampUint64(memStats.HeapIdle))
|
||||||
|
o.ObserveInt64(heapInuse, clampUint64(memStats.HeapInuse))
|
||||||
|
o.ObserveInt64(heapObjects, clampUint64(memStats.HeapObjects))
|
||||||
|
o.ObserveInt64(heapReleased, clampUint64(memStats.HeapReleased))
|
||||||
|
o.ObserveInt64(heapSys, clampUint64(memStats.HeapSys))
|
||||||
|
o.ObserveInt64(liveObjects, clampUint64(memStats.Mallocs-memStats.Frees))
|
||||||
|
o.ObserveInt64(ptrLookups, clampUint64(memStats.Lookups))
|
||||||
|
o.ObserveInt64(gcCount, int64(memStats.NumGC))
|
||||||
|
o.ObserveInt64(pauseTotalNs, clampUint64(memStats.PauseTotalNs))
|
||||||
|
|
||||||
|
computeGCPauses(ctx, gcPauseNs, memStats.PauseNs[:], lastNumGC, memStats.NumGC)
|
||||||
|
|
||||||
|
lastNumGC = memStats.NumGC
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
heapAlloc,
|
||||||
|
heapIdle,
|
||||||
|
heapInuse,
|
||||||
|
heapObjects,
|
||||||
|
heapReleased,
|
||||||
|
heapSys,
|
||||||
|
liveObjects,
|
||||||
|
|
||||||
|
ptrLookups,
|
||||||
|
|
||||||
|
gcCount,
|
||||||
|
pauseTotalNs,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clampUint64(v uint64) int64 {
|
||||||
|
if v > math.MaxInt64 {
|
||||||
|
return math.MaxInt64
|
||||||
|
}
|
||||||
|
return int64(v) // nolint: gosec // Overflow checked above.
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeGCPauses(
|
||||||
|
ctx context.Context,
|
||||||
|
recorder metric.Int64Histogram,
|
||||||
|
circular []uint64,
|
||||||
|
lastNumGC, currentNumGC uint32,
|
||||||
|
) {
|
||||||
|
delta := int(int64(currentNumGC) - int64(lastNumGC))
|
||||||
|
|
||||||
|
if delta == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if delta >= len(circular) {
|
||||||
|
// There were > 256 collections, some may have been lost.
|
||||||
|
recordGCPauses(ctx, recorder, circular)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n := len(circular)
|
||||||
|
if n < 0 {
|
||||||
|
// Only the case in error situations.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
length := uint64(n) // nolint: gosec // n >= 0
|
||||||
|
|
||||||
|
i := uint64(lastNumGC) % length
|
||||||
|
j := uint64(currentNumGC) % length
|
||||||
|
|
||||||
|
if j < i { // wrap around the circular buffer
|
||||||
|
recordGCPauses(ctx, recorder, circular[i:])
|
||||||
|
recordGCPauses(ctx, recorder, circular[:j])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recordGCPauses(ctx, recorder, circular[i:j])
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordGCPauses(
|
||||||
|
ctx context.Context,
|
||||||
|
recorder metric.Int64Histogram,
|
||||||
|
pauses []uint64,
|
||||||
|
) {
|
||||||
|
for _, pause := range pauses {
|
||||||
|
recorder.Record(ctx, clampUint64(pause))
|
||||||
|
}
|
||||||
|
}
|
38
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/x/README.md
generated
vendored
Normal file
38
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/x/README.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Feature Gates
|
||||||
|
|
||||||
|
The runtime package contains a feature gate used to ease the migration
|
||||||
|
from the [previous runtime metrics conventions] to the new [OpenTelemetry Go
|
||||||
|
Runtime conventions].
|
||||||
|
|
||||||
|
Note that the new runtime metrics conventions are still experimental, and may
|
||||||
|
change in backwards incompatible ways as feedback is applied.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [Include Deprecated Metrics](#include-deprecated-metrics)
|
||||||
|
|
||||||
|
### Include Deprecated Metrics
|
||||||
|
|
||||||
|
Once new experimental runtime metrics are added, they will be produced
|
||||||
|
**in addition to** the existing runtime metrics. Users that migrate right away
|
||||||
|
can disable the old runtime metrics:
|
||||||
|
|
||||||
|
```console
|
||||||
|
export OTEL_GO_X_DEPRECATED_RUNTIME_METRICS=false
|
||||||
|
```
|
||||||
|
|
||||||
|
In a later release, the deprecated runtime metrics will stop being produced by
|
||||||
|
default. To temporarily re-enable the deprecated metrics:
|
||||||
|
|
||||||
|
```console
|
||||||
|
export OTEL_GO_X_DEPRECATED_RUNTIME_METRICS=true
|
||||||
|
```
|
||||||
|
|
||||||
|
After two additional releases, the deprecated runtime metrics will be removed,
|
||||||
|
and setting the environment variable will no longer have any effect.
|
||||||
|
|
||||||
|
The value set must be the case-insensitive string of `"true"` to enable the
|
||||||
|
feature, and `"false"` to disable the feature. All other values are ignored.
|
||||||
|
|
||||||
|
[previous runtime metrics conventions]: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/runtime@v0.52.0
|
||||||
|
[OpenTelemetry Go Runtime conventions]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/runtime/go-metrics.md
|
53
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/x/x.go
generated
vendored
Normal file
53
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/internal/x/x.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package x contains support for OTel runtime instrumentation experimental features.
|
||||||
|
//
|
||||||
|
// This package should only be used for features defined in the specification.
|
||||||
|
// It should not be used for experiments or new project ideas.
|
||||||
|
package x // import "go.opentelemetry.io/contrib/instrumentation/runtime/internal/x"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeprecatedRuntimeMetrics is an experimental feature flag that defines if the deprecated
|
||||||
|
// runtime metrics should be produced. During development of the new
|
||||||
|
// conventions, it is enabled by default.
|
||||||
|
//
|
||||||
|
// To disable this feature set the OTEL_GO_X_DEPRECATED_RUNTIME_METRICS environment variable
|
||||||
|
// to the case-insensitive string value of "false" (i.e. "False" and "FALSE"
|
||||||
|
// will also enable this).
|
||||||
|
var DeprecatedRuntimeMetrics = newFeature("DEPRECATED_RUNTIME_METRICS", true)
|
||||||
|
|
||||||
|
// BoolFeature is an experimental feature control flag. It provides a uniform way
|
||||||
|
// to interact with these feature flags and parse their values.
|
||||||
|
type BoolFeature struct {
|
||||||
|
key string
|
||||||
|
defaultVal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFeature(suffix string, defaultVal bool) BoolFeature {
|
||||||
|
const envKeyRoot = "OTEL_GO_X_"
|
||||||
|
return BoolFeature{
|
||||||
|
key: envKeyRoot + suffix,
|
||||||
|
defaultVal: defaultVal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key returns the environment variable key that needs to be set to enable the
|
||||||
|
// feature.
|
||||||
|
func (f BoolFeature) Key() string { return f.key }
|
||||||
|
|
||||||
|
// Enabled returns if the feature is enabled.
|
||||||
|
func (f BoolFeature) Enabled() bool {
|
||||||
|
v := os.Getenv(f.key)
|
||||||
|
if strings.ToLower(v) == "false" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.ToLower(v) == "true" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return f.defaultVal
|
||||||
|
}
|
99
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/options.go
generated
vendored
Normal file
99
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/options.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
)
|
||||||
|
|
||||||
|
// config contains optional settings for reporting runtime metrics.
|
||||||
|
type config struct {
|
||||||
|
// MinimumReadMemStatsInterval sets the minimum interval
|
||||||
|
// between calls to runtime.ReadMemStats(). Negative values
|
||||||
|
// are ignored.
|
||||||
|
MinimumReadMemStatsInterval time.Duration
|
||||||
|
|
||||||
|
// MeterProvider sets the metric.MeterProvider. If nil, the global
|
||||||
|
// Provider will be used.
|
||||||
|
MeterProvider metric.MeterProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option supports configuring optional settings for runtime metrics.
|
||||||
|
type Option interface {
|
||||||
|
apply(*config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProducerOption supports configuring optional settings for runtime metrics using a
|
||||||
|
// metric producer in addition to standard instrumentation.
|
||||||
|
type ProducerOption interface {
|
||||||
|
Option
|
||||||
|
applyProducer(*config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultMinimumReadMemStatsInterval is the default minimum interval
|
||||||
|
// between calls to runtime.ReadMemStats(). Use the
|
||||||
|
// WithMinimumReadMemStatsInterval() option to modify this setting in
|
||||||
|
// Start().
|
||||||
|
const DefaultMinimumReadMemStatsInterval time.Duration = 15 * time.Second
|
||||||
|
|
||||||
|
// WithMinimumReadMemStatsInterval sets a minimum interval between calls to
|
||||||
|
// runtime.ReadMemStats(), which is a relatively expensive call to make
|
||||||
|
// frequently. This setting is ignored when `d` is negative.
|
||||||
|
func WithMinimumReadMemStatsInterval(d time.Duration) Option {
|
||||||
|
return minimumReadMemStatsIntervalOption(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
type minimumReadMemStatsIntervalOption time.Duration
|
||||||
|
|
||||||
|
func (o minimumReadMemStatsIntervalOption) apply(c *config) {
|
||||||
|
if o >= 0 {
|
||||||
|
c.MinimumReadMemStatsInterval = time.Duration(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o minimumReadMemStatsIntervalOption) applyProducer(c *config) { o.apply(c) }
|
||||||
|
|
||||||
|
// WithMeterProvider sets the Metric implementation to use for
|
||||||
|
// reporting. If this option is not used, the global metric.MeterProvider
|
||||||
|
// will be used. `provider` must be non-nil.
|
||||||
|
func WithMeterProvider(provider metric.MeterProvider) Option {
|
||||||
|
return metricProviderOption{provider}
|
||||||
|
}
|
||||||
|
|
||||||
|
type metricProviderOption struct{ metric.MeterProvider }
|
||||||
|
|
||||||
|
func (o metricProviderOption) apply(c *config) {
|
||||||
|
if o.MeterProvider != nil {
|
||||||
|
c.MeterProvider = o.MeterProvider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newConfig computes a config from the supplied Options.
|
||||||
|
func newConfig(opts ...Option) config {
|
||||||
|
c := config{
|
||||||
|
MeterProvider: otel.GetMeterProvider(),
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt.apply(&c)
|
||||||
|
}
|
||||||
|
if c.MinimumReadMemStatsInterval <= 0 {
|
||||||
|
c.MinimumReadMemStatsInterval = DefaultMinimumReadMemStatsInterval
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// newConfig computes a config from the supplied ProducerOptions.
|
||||||
|
func newProducerConfig(opts ...ProducerOption) config {
|
||||||
|
c := config{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt.applyProducer(&c)
|
||||||
|
}
|
||||||
|
if c.MinimumReadMemStatsInterval <= 0 {
|
||||||
|
c.MinimumReadMemStatsInterval = DefaultMinimumReadMemStatsInterval
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
120
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/producer.go
generated
vendored
Normal file
120
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/producer.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"runtime/metrics"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||||
|
"go.opentelemetry.io/otel/sdk/metric"
|
||||||
|
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var startTime time.Time
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
startTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
var histogramMetrics = []string{goSchedLatencies}
|
||||||
|
|
||||||
|
// Producer is a metric.Producer, which provides precomputed histogram metrics from the go runtime.
|
||||||
|
type Producer struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
collector *goCollector
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ metric.Producer = (*Producer)(nil)
|
||||||
|
|
||||||
|
// NewProducer creates a Producer which provides precomputed histogram metrics from the go runtime.
|
||||||
|
func NewProducer(opts ...ProducerOption) *Producer {
|
||||||
|
c := newProducerConfig(opts...)
|
||||||
|
return &Producer{
|
||||||
|
collector: newCollector(c.MinimumReadMemStatsInterval, histogramMetrics),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce returns precomputed histogram metrics from the go runtime, or an error if unsuccessful.
|
||||||
|
func (p *Producer) Produce(context.Context) ([]metricdata.ScopeMetrics, error) {
|
||||||
|
p.lock.Lock()
|
||||||
|
p.collector.refresh()
|
||||||
|
schedHist := p.collector.getHistogram(goSchedLatencies)
|
||||||
|
p.lock.Unlock()
|
||||||
|
// Use the last collection time (which may or may not be now) for the timestamp.
|
||||||
|
histDp := convertRuntimeHistogram(schedHist, p.collector.lastCollect)
|
||||||
|
if len(histDp) == 0 {
|
||||||
|
return nil, errors.New("unable to obtain go.schedule.duration metric from the runtime")
|
||||||
|
}
|
||||||
|
return []metricdata.ScopeMetrics{
|
||||||
|
{
|
||||||
|
Scope: instrumentation.Scope{
|
||||||
|
Name: ScopeName,
|
||||||
|
Version: Version(),
|
||||||
|
},
|
||||||
|
Metrics: []metricdata.Metrics{
|
||||||
|
{
|
||||||
|
Name: "go.schedule.duration",
|
||||||
|
Description: "The time goroutines have spent in the scheduler in a runnable state before actually running.",
|
||||||
|
Unit: "s",
|
||||||
|
Data: metricdata.Histogram[float64]{
|
||||||
|
Temporality: metricdata.CumulativeTemporality,
|
||||||
|
DataPoints: histDp,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptySet = attribute.EmptySet()
|
||||||
|
|
||||||
|
func convertRuntimeHistogram(runtimeHist *metrics.Float64Histogram, ts time.Time) []metricdata.HistogramDataPoint[float64] {
|
||||||
|
if runtimeHist == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bounds := runtimeHist.Buckets
|
||||||
|
counts := runtimeHist.Counts
|
||||||
|
if len(bounds) < 2 {
|
||||||
|
// runtime histograms are guaranteed to have at least two bucket boundaries.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// trim the first bucket since it is a lower bound. OTel histogram boundaries only have an upper bound.
|
||||||
|
bounds = bounds[1:]
|
||||||
|
if bounds[len(bounds)-1] == math.Inf(1) {
|
||||||
|
// trim the last bucket if it is +Inf, since the +Inf boundary is implicit in OTel.
|
||||||
|
bounds = bounds[:len(bounds)-1]
|
||||||
|
} else {
|
||||||
|
// if the last bucket is not +Inf, append an extra zero count since
|
||||||
|
// the implicit +Inf bucket won't have any observations.
|
||||||
|
counts = append(counts, 0)
|
||||||
|
}
|
||||||
|
count := uint64(0)
|
||||||
|
sum := float64(0)
|
||||||
|
for i, c := range counts {
|
||||||
|
count += c
|
||||||
|
// This computed sum is an underestimate, since it assumes each
|
||||||
|
// observation happens at the bucket's lower bound.
|
||||||
|
if i > 0 && count != 0 {
|
||||||
|
sum += bounds[i-1] * float64(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []metricdata.HistogramDataPoint[float64]{
|
||||||
|
{
|
||||||
|
StartTime: startTime,
|
||||||
|
Count: count,
|
||||||
|
Sum: sum,
|
||||||
|
Time: ts,
|
||||||
|
Bounds: bounds,
|
||||||
|
BucketCounts: counts,
|
||||||
|
Attributes: *emptySet,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
229
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/runtime.go
generated
vendored
Normal file
229
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/runtime.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math"
|
||||||
|
"runtime/metrics"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/runtime/internal/x"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ScopeName is the instrumentation scope name.
|
||||||
|
const ScopeName = "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
|
|
||||||
|
const (
|
||||||
|
goTotalMemory = "/memory/classes/total:bytes"
|
||||||
|
goMemoryReleased = "/memory/classes/heap/released:bytes"
|
||||||
|
goHeapMemory = "/memory/classes/heap/stacks:bytes"
|
||||||
|
goMemoryLimit = "/gc/gomemlimit:bytes"
|
||||||
|
goMemoryAllocated = "/gc/heap/allocs:bytes"
|
||||||
|
goMemoryAllocations = "/gc/heap/allocs:objects"
|
||||||
|
goMemoryGoal = "/gc/heap/goal:bytes"
|
||||||
|
goGoroutines = "/sched/goroutines:goroutines"
|
||||||
|
goMaxProcs = "/sched/gomaxprocs:threads"
|
||||||
|
goConfigGC = "/gc/gogc:percent"
|
||||||
|
goSchedLatencies = "/sched/latencies:seconds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Start initializes reporting of runtime metrics using the supplied config.
|
||||||
|
// For goroutine scheduling metrics, additionally see [NewProducer].
|
||||||
|
func Start(opts ...Option) error {
|
||||||
|
c := newConfig(opts...)
|
||||||
|
meter := c.MeterProvider.Meter(
|
||||||
|
ScopeName,
|
||||||
|
metric.WithInstrumentationVersion(Version()),
|
||||||
|
)
|
||||||
|
if x.DeprecatedRuntimeMetrics.Enabled() {
|
||||||
|
return deprecatedruntime.Start(meter, c.MinimumReadMemStatsInterval)
|
||||||
|
}
|
||||||
|
memoryUsedInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.memory.used",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Memory used by the Go runtime."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
memoryLimitInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.memory.limit",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Go runtime memory limit configured by the user, if a limit exists."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
memoryAllocatedInstrument, err := meter.Int64ObservableCounter(
|
||||||
|
"go.memory.allocated",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Memory allocated to the heap by the application."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
memoryAllocationsInstrument, err := meter.Int64ObservableCounter(
|
||||||
|
"go.memory.allocations",
|
||||||
|
metric.WithUnit("{allocation}"),
|
||||||
|
metric.WithDescription("Count of allocations to the heap by the application."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
memoryGCGoalInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.memory.gc.goal",
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithDescription("Heap size target for the end of the GC cycle."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
goroutineCountInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.goroutine.count",
|
||||||
|
metric.WithUnit("{goroutine}"),
|
||||||
|
metric.WithDescription("Count of live goroutines."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
processorLimitInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.processor.limit",
|
||||||
|
metric.WithUnit("{thread}"),
|
||||||
|
metric.WithDescription("The number of OS threads that can execute user-level Go code simultaneously."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gogcConfigInstrument, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"go.config.gogc",
|
||||||
|
metric.WithUnit("%"),
|
||||||
|
metric.WithDescription("Heap size target percentage configured by the user, otherwise 100."),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
otherMemoryOpt := metric.WithAttributeSet(
|
||||||
|
attribute.NewSet(attribute.String("go.memory.type", "other")),
|
||||||
|
)
|
||||||
|
stackMemoryOpt := metric.WithAttributeSet(
|
||||||
|
attribute.NewSet(attribute.String("go.memory.type", "stack")),
|
||||||
|
)
|
||||||
|
collector := newCollector(c.MinimumReadMemStatsInterval, runtimeMetrics)
|
||||||
|
var lock sync.Mutex
|
||||||
|
_, err = meter.RegisterCallback(
|
||||||
|
func(ctx context.Context, o metric.Observer) error {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
collector.refresh()
|
||||||
|
stackMemory := collector.getInt(goHeapMemory)
|
||||||
|
o.ObserveInt64(memoryUsedInstrument, stackMemory, stackMemoryOpt)
|
||||||
|
totalMemory := collector.getInt(goTotalMemory) - collector.getInt(goMemoryReleased)
|
||||||
|
otherMemory := totalMemory - stackMemory
|
||||||
|
o.ObserveInt64(memoryUsedInstrument, otherMemory, otherMemoryOpt)
|
||||||
|
// Only observe the limit metric if a limit exists
|
||||||
|
if limit := collector.getInt(goMemoryLimit); limit != math.MaxInt64 {
|
||||||
|
o.ObserveInt64(memoryLimitInstrument, limit)
|
||||||
|
}
|
||||||
|
o.ObserveInt64(memoryAllocatedInstrument, collector.getInt(goMemoryAllocated))
|
||||||
|
o.ObserveInt64(memoryAllocationsInstrument, collector.getInt(goMemoryAllocations))
|
||||||
|
o.ObserveInt64(memoryGCGoalInstrument, collector.getInt(goMemoryGoal))
|
||||||
|
o.ObserveInt64(goroutineCountInstrument, collector.getInt(goGoroutines))
|
||||||
|
o.ObserveInt64(processorLimitInstrument, collector.getInt(goMaxProcs))
|
||||||
|
o.ObserveInt64(gogcConfigInstrument, collector.getInt(goConfigGC))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
memoryUsedInstrument,
|
||||||
|
memoryLimitInstrument,
|
||||||
|
memoryAllocatedInstrument,
|
||||||
|
memoryAllocationsInstrument,
|
||||||
|
memoryGCGoalInstrument,
|
||||||
|
goroutineCountInstrument,
|
||||||
|
processorLimitInstrument,
|
||||||
|
gogcConfigInstrument,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the metrics we actually fetch from the go runtime.
|
||||||
|
var runtimeMetrics = []string{
|
||||||
|
goTotalMemory,
|
||||||
|
goMemoryReleased,
|
||||||
|
goHeapMemory,
|
||||||
|
goMemoryLimit,
|
||||||
|
goMemoryAllocated,
|
||||||
|
goMemoryAllocations,
|
||||||
|
goMemoryGoal,
|
||||||
|
goGoroutines,
|
||||||
|
goMaxProcs,
|
||||||
|
goConfigGC,
|
||||||
|
}
|
||||||
|
|
||||||
|
type goCollector struct {
|
||||||
|
// now is used to replace the implementation of time.Now for testing
|
||||||
|
now func() time.Time
|
||||||
|
// lastCollect tracks the last time metrics were refreshed
|
||||||
|
lastCollect time.Time
|
||||||
|
// minimumInterval is the minimum amount of time between calls to metrics.Read
|
||||||
|
minimumInterval time.Duration
|
||||||
|
// sampleBuffer is populated by runtime/metrics
|
||||||
|
sampleBuffer []metrics.Sample
|
||||||
|
// sampleMap allows us to easily get the value of a single metric
|
||||||
|
sampleMap map[string]*metrics.Sample
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCollector(minimumInterval time.Duration, metricNames []string) *goCollector {
|
||||||
|
g := &goCollector{
|
||||||
|
sampleBuffer: make([]metrics.Sample, 0, len(metricNames)),
|
||||||
|
sampleMap: make(map[string]*metrics.Sample, len(metricNames)),
|
||||||
|
minimumInterval: minimumInterval,
|
||||||
|
now: time.Now,
|
||||||
|
}
|
||||||
|
for _, metricName := range metricNames {
|
||||||
|
g.sampleBuffer = append(g.sampleBuffer, metrics.Sample{Name: metricName})
|
||||||
|
// sampleMap references a position in the sampleBuffer slice. If an
|
||||||
|
// element is appended to sampleBuffer, it must be added to sampleMap
|
||||||
|
// for the sample to be accessible in sampleMap.
|
||||||
|
g.sampleMap[metricName] = &g.sampleBuffer[len(g.sampleBuffer)-1]
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *goCollector) refresh() {
|
||||||
|
now := g.now()
|
||||||
|
if now.Sub(g.lastCollect) < g.minimumInterval {
|
||||||
|
// refresh was invoked more frequently than allowed by the minimum
|
||||||
|
// interval. Do nothing.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metrics.Read(g.sampleBuffer)
|
||||||
|
g.lastCollect = now
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *goCollector) getInt(name string) int64 {
|
||||||
|
if s, ok := g.sampleMap[name]; ok && s.Value.Kind() == metrics.KindUint64 {
|
||||||
|
v := s.Value.Uint64()
|
||||||
|
if v > math.MaxInt64 {
|
||||||
|
return math.MaxInt64
|
||||||
|
}
|
||||||
|
return int64(v) // nolint: gosec // Overflow checked above.
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *goCollector) getHistogram(name string) *metrics.Float64Histogram {
|
||||||
|
if s, ok := g.sampleMap[name]; ok && s.Value.Kind() == metrics.KindFloat64Histogram {
|
||||||
|
return s.Value.Float64Histogram()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
17
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/version.go
generated
vendored
Normal file
17
vendor/go.opentelemetry.io/contrib/instrumentation/runtime/version.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||||
|
|
||||||
|
// Version is the current release version of the runtime instrumentation.
|
||||||
|
func Version() string {
|
||||||
|
return "0.60.0"
|
||||||
|
// This string is updated by the pre_release.sh script during release
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemVersion is the semantic version to be supplied to tracer/meter creation.
|
||||||
|
//
|
||||||
|
// Deprecated: Use [Version] instead.
|
||||||
|
func SemVersion() string {
|
||||||
|
return Version()
|
||||||
|
}
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@@ -984,6 +984,11 @@ go.opentelemetry.io/contrib/bridges/prometheus
|
|||||||
# go.opentelemetry.io/contrib/exporters/autoexport v0.60.0
|
# go.opentelemetry.io/contrib/exporters/autoexport v0.60.0
|
||||||
## explicit; go 1.22.0
|
## explicit; go 1.22.0
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport
|
go.opentelemetry.io/contrib/exporters/autoexport
|
||||||
|
# go.opentelemetry.io/contrib/instrumentation/runtime v0.60.0
|
||||||
|
## explicit; go 1.22.0
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/runtime/internal/x
|
||||||
# go.opentelemetry.io/otel v1.35.0
|
# go.opentelemetry.io/otel v1.35.0
|
||||||
## explicit; go 1.22.0
|
## explicit; go 1.22.0
|
||||||
go.opentelemetry.io/otel
|
go.opentelemetry.io/otel
|
||||||
|
Reference in New Issue
Block a user