deps: update images to 0.94
Signed-off-by: Simon de Vlieger <supakeen@redhat.com>
This commit is contained in:
parent
4f90a757dc
commit
bccd1639af
1096 changed files with 411794 additions and 11488 deletions
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/LICENSE
generated
vendored
Normal file
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
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.
|
||||
3
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/README.md
generated
vendored
Normal file
3
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# GCP Resource detection library
|
||||
|
||||
This is a library intended to be used by Upstream OpenTelemetry resource detectors. It exists within this repository to allow for integration testing of the detection functions in real GCP environments.
|
||||
76
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/app_engine.go
generated
vendored
Normal file
76
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/app_engine.go
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
const (
|
||||
// See https://cloud.google.com/appengine/docs/flexible/python/migrating#modules
|
||||
// for the environment variables available in GAE environments.
|
||||
gaeServiceEnv = "GAE_SERVICE"
|
||||
gaeVersionEnv = "GAE_VERSION"
|
||||
gaeInstanceEnv = "GAE_INSTANCE"
|
||||
gaeEnv = "GAE_ENV"
|
||||
gaeStandard = "standard"
|
||||
)
|
||||
|
||||
func (d *Detector) onAppEngineStandard() bool {
|
||||
// See https://cloud.google.com/appengine/docs/standard/go111/runtime#environment_variables.
|
||||
env, found := d.os.LookupEnv(gaeEnv)
|
||||
return found && env == gaeStandard
|
||||
}
|
||||
|
||||
func (d *Detector) onAppEngine() bool {
|
||||
_, found := d.os.LookupEnv(gaeServiceEnv)
|
||||
return found
|
||||
}
|
||||
|
||||
// AppEngineServiceName returns the service name of the app engine service.
|
||||
func (d *Detector) AppEngineServiceName() (string, error) {
|
||||
if name, found := d.os.LookupEnv(gaeServiceEnv); found {
|
||||
return name, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// AppEngineServiceVersion returns the service version of the app engine service.
|
||||
func (d *Detector) AppEngineServiceVersion() (string, error) {
|
||||
if version, found := d.os.LookupEnv(gaeVersionEnv); found {
|
||||
return version, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// AppEngineServiceInstance returns the service instance of the app engine service.
|
||||
func (d *Detector) AppEngineServiceInstance() (string, error) {
|
||||
if instanceID, found := d.os.LookupEnv(gaeInstanceEnv); found {
|
||||
return instanceID, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// AppEngineFlexAvailabilityZoneAndRegion returns the zone and region in which this program is running.
|
||||
func (d *Detector) AppEngineFlexAvailabilityZoneAndRegion() (string, string, error) {
|
||||
// The GCE metadata server is available on App Engine Flex.
|
||||
return d.GCEAvailabilityZoneAndRegion()
|
||||
}
|
||||
|
||||
// AppEngineStandardAvailabilityZone returns the zone the app engine service is running in.
|
||||
func (d *Detector) AppEngineStandardAvailabilityZone() (string, error) {
|
||||
return d.metadata.Zone()
|
||||
}
|
||||
|
||||
// AppEngineStandardCloudRegion returns the region the app engine service is running in.
|
||||
func (d *Detector) AppEngineStandardCloudRegion() (string, error) {
|
||||
return d.FaaSCloudRegion()
|
||||
}
|
||||
55
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/bms.go
generated
vendored
Normal file
55
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/bms.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
const (
|
||||
bmsProjectIDEnv = "BMS_PROJECT_ID"
|
||||
bmsRegionEnv = "BMS_REGION"
|
||||
bmsInstanceIDEnv = "BMS_INSTANCE_ID"
|
||||
)
|
||||
|
||||
// onBareMetalSolution checks if the code is running on a Google Cloud Bare Metal Solution (BMS) by verifying
|
||||
// the presence and non-empty values of BMS_PROJECT_ID, BMS_REGION, and BMS_INSTANCE_ID environment variables.
|
||||
// For more information on Google Cloud Bare Metal Solution, see: https://cloud.google.com/bare-metal/docs
|
||||
func (d *Detector) onBareMetalSolution() bool {
|
||||
projectID, projectIDExists := d.os.LookupEnv(bmsProjectIDEnv)
|
||||
region, regionExists := d.os.LookupEnv(bmsRegionEnv)
|
||||
instanceID, instanceIDExists := d.os.LookupEnv(bmsInstanceIDEnv)
|
||||
return projectIDExists && regionExists && instanceIDExists && projectID != "" && region != "" && instanceID != ""
|
||||
}
|
||||
|
||||
// BareMetalSolutionInstanceID returns the instance ID from the BMS_INSTANCE_ID environment variable.
|
||||
func (d *Detector) BareMetalSolutionInstanceID() (string, error) {
|
||||
if instanceID, found := d.os.LookupEnv(bmsInstanceIDEnv); found {
|
||||
return instanceID, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// BareMetalSolutionCloudRegion returns the region from the BMS_REGION environment variable.
|
||||
func (d *Detector) BareMetalSolutionCloudRegion() (string, error) {
|
||||
if region, found := d.os.LookupEnv(bmsRegionEnv); found {
|
||||
return region, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// BareMetalSolutionProjectID returns the project ID from the BMS_PROJECT_ID environment variable.
|
||||
func (d *Detector) BareMetalSolutionProjectID() (string, error) {
|
||||
if project, found := d.os.LookupEnv(bmsProjectIDEnv); found {
|
||||
return project, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
102
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/detector.go
generated
vendored
Normal file
102
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/detector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
)
|
||||
|
||||
var errEnvVarNotFound = errors.New("environment variable not found")
|
||||
|
||||
// NewDetector returns a *Detector which can get detect the platform,
|
||||
// and fetch attributes of the platform on which it is running.
|
||||
func NewDetector() *Detector {
|
||||
return &Detector{metadata: metadata.NewClient(nil), os: realOSProvider{}}
|
||||
}
|
||||
|
||||
type Platform int64
|
||||
|
||||
const (
|
||||
UnknownPlatform Platform = iota
|
||||
GKE
|
||||
GCE
|
||||
CloudRun
|
||||
CloudRunJob
|
||||
CloudFunctions
|
||||
AppEngineStandard
|
||||
AppEngineFlex
|
||||
BareMetalSolution
|
||||
)
|
||||
|
||||
// CloudPlatform returns the platform on which this program is running.
|
||||
func (d *Detector) CloudPlatform() Platform {
|
||||
switch {
|
||||
case d.onBareMetalSolution():
|
||||
return BareMetalSolution
|
||||
case d.onGKE():
|
||||
return GKE
|
||||
case d.onCloudFunctions():
|
||||
return CloudFunctions
|
||||
case d.onCloudRun():
|
||||
return CloudRun
|
||||
case d.onCloudRunJob():
|
||||
return CloudRunJob
|
||||
case d.onAppEngineStandard():
|
||||
return AppEngineStandard
|
||||
case d.onAppEngine():
|
||||
return AppEngineFlex
|
||||
case d.onGCE():
|
||||
return GCE
|
||||
}
|
||||
return UnknownPlatform
|
||||
}
|
||||
|
||||
// ProjectID returns the ID of the project in which this program is running.
|
||||
func (d *Detector) ProjectID() (string, error) {
|
||||
return d.metadata.ProjectID()
|
||||
}
|
||||
|
||||
// Detector collects resource information for all GCP platforms.
|
||||
type Detector struct {
|
||||
metadata metadataProvider
|
||||
os osProvider
|
||||
}
|
||||
|
||||
// metadataProvider contains the subset of the metadata.Client functions used
|
||||
// by this resource Detector to allow testing with a fake implementation.
|
||||
type metadataProvider interface {
|
||||
ProjectID() (string, error)
|
||||
InstanceID() (string, error)
|
||||
Get(string) (string, error)
|
||||
InstanceName() (string, error)
|
||||
Hostname() (string, error)
|
||||
Zone() (string, error)
|
||||
InstanceAttributeValue(string) (string, error)
|
||||
}
|
||||
|
||||
// osProvider contains the subset of the os package functions used by.
|
||||
type osProvider interface {
|
||||
LookupEnv(string) (string, bool)
|
||||
}
|
||||
|
||||
// realOSProvider uses the os package to lookup env vars.
|
||||
type realOSProvider struct{}
|
||||
|
||||
func (realOSProvider) LookupEnv(env string) (string, bool) {
|
||||
return os.LookupEnv(env)
|
||||
}
|
||||
105
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/faas.go
generated
vendored
Normal file
105
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/faas.go
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Cloud Functions env vars:
|
||||
// https://cloud.google.com/functions/docs/configuring/env-var#newer_runtimes
|
||||
//
|
||||
// Cloud Run env vars:
|
||||
// https://cloud.google.com/run/docs/container-contract#services-env-vars
|
||||
//
|
||||
// Cloud Run jobs env vars:
|
||||
// https://cloud.google.com/run/docs/container-contract#jobs-env-vars
|
||||
cloudFunctionsTargetEnv = "FUNCTION_TARGET"
|
||||
cloudRunConfigurationEnv = "K_CONFIGURATION"
|
||||
cloudRunJobsEnv = "CLOUD_RUN_JOB"
|
||||
faasServiceEnv = "K_SERVICE"
|
||||
faasRevisionEnv = "K_REVISION"
|
||||
cloudRunJobExecutionEnv = "CLOUD_RUN_EXECUTION"
|
||||
cloudRunJobTaskIndexEnv = "CLOUD_RUN_TASK_INDEX"
|
||||
regionMetadataAttr = "instance/region"
|
||||
)
|
||||
|
||||
func (d *Detector) onCloudFunctions() bool {
|
||||
_, found := d.os.LookupEnv(cloudFunctionsTargetEnv)
|
||||
return found
|
||||
}
|
||||
|
||||
func (d *Detector) onCloudRun() bool {
|
||||
_, found := d.os.LookupEnv(cloudRunConfigurationEnv)
|
||||
return found
|
||||
}
|
||||
|
||||
func (d *Detector) onCloudRunJob() bool {
|
||||
_, found := d.os.LookupEnv(cloudRunJobsEnv)
|
||||
return found
|
||||
}
|
||||
|
||||
// FaaSName returns the name of the Cloud Run, Cloud Run jobs or Cloud Functions service.
|
||||
func (d *Detector) FaaSName() (string, error) {
|
||||
if name, found := d.os.LookupEnv(faasServiceEnv); found {
|
||||
return name, nil
|
||||
}
|
||||
if name, found := d.os.LookupEnv(cloudRunJobsEnv); found {
|
||||
return name, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// FaaSVersion returns the revision of the Cloud Run or Cloud Functions service.
|
||||
func (d *Detector) FaaSVersion() (string, error) {
|
||||
if version, found := d.os.LookupEnv(faasRevisionEnv); found {
|
||||
return version, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// CloudRunJobExecution returns the execution id of the Cloud Run jobs.
|
||||
func (d *Detector) CloudRunJobExecution() (string, error) {
|
||||
if eid, found := d.os.LookupEnv(cloudRunJobExecutionEnv); found {
|
||||
return eid, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// CloudRunJobTaskIndex returns the task index for the execution of the Cloud Run jobs.
|
||||
func (d *Detector) CloudRunJobTaskIndex() (string, error) {
|
||||
if tidx, found := d.os.LookupEnv(cloudRunJobTaskIndexEnv); found {
|
||||
return tidx, nil
|
||||
}
|
||||
return "", errEnvVarNotFound
|
||||
}
|
||||
|
||||
// FaaSID returns the instance id of the Cloud Run or Cloud Function.
|
||||
func (d *Detector) FaaSID() (string, error) {
|
||||
return d.metadata.InstanceID()
|
||||
}
|
||||
|
||||
// FaaSCloudRegion detects region from the metadata server.
|
||||
// It is in the format /projects/<project_number>/regions/<region>.
|
||||
//
|
||||
// https://cloud.google.com/run/docs/reference/container-contract#metadata-server
|
||||
func (d *Detector) FaaSCloudRegion() (string, error) {
|
||||
region, err := d.metadata.Get(regionMetadataAttr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return region[strings.LastIndex(region, "/")+1:], nil
|
||||
}
|
||||
75
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/gce.go
generated
vendored
Normal file
75
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/gce.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// See the available GCE instance metadata:
|
||||
// https://cloud.google.com/compute/docs/metadata/default-metadata-values#vm_instance_metadata
|
||||
const machineTypeMetadataAttr = "instance/machine-type"
|
||||
|
||||
func (d *Detector) onGCE() bool {
|
||||
_, err := d.metadata.Get(machineTypeMetadataAttr)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// GCEHostType returns the machine type of the instance on which this program is running.
|
||||
func (d *Detector) GCEHostType() (string, error) {
|
||||
return d.metadata.Get(machineTypeMetadataAttr)
|
||||
}
|
||||
|
||||
// GCEHostID returns the instance ID of the instance on which this program is running.
|
||||
func (d *Detector) GCEHostID() (string, error) {
|
||||
return d.metadata.InstanceID()
|
||||
}
|
||||
|
||||
// GCEHostName returns the instance name of the instance on which this program is running.
|
||||
// Recommended to use GCEInstanceName() or GCEInstanceHostname() to more accurately reflect which
|
||||
// value is returned.
|
||||
func (d *Detector) GCEHostName() (string, error) {
|
||||
return d.metadata.InstanceName()
|
||||
}
|
||||
|
||||
// GCEInstanceName returns the instance name of the instance on which this program is running.
|
||||
// This is the value visible in the Cloud Console UI, and the prefix for the default hostname
|
||||
// of the instance as defined by the default internal DNS name (see https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names).
|
||||
func (d *Detector) GCEInstanceName() (string, error) {
|
||||
return d.metadata.InstanceName()
|
||||
}
|
||||
|
||||
// GCEInstanceHostname returns the full value of the default or custom hostname of the instance
|
||||
// on which this program is running. See https://cloud.google.com/compute/docs/instances/custom-hostname-vm.
|
||||
func (d *Detector) GCEInstanceHostname() (string, error) {
|
||||
return d.metadata.Hostname()
|
||||
}
|
||||
|
||||
// GCEAvailabilityZoneAndRegion returns the zone and region in which this program is running.
|
||||
func (d *Detector) GCEAvailabilityZoneAndRegion() (string, string, error) {
|
||||
zone, err := d.metadata.Zone()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if zone == "" {
|
||||
return "", "", fmt.Errorf("no zone detected from GCE metadata server")
|
||||
}
|
||||
splitZone := strings.SplitN(zone, "-", 3)
|
||||
if len(splitZone) != 3 {
|
||||
return "", "", fmt.Errorf("zone was not in the expected format: country-region-zone. Got %v", zone)
|
||||
}
|
||||
return zone, strings.Join(splitZone[0:2], "-"), nil
|
||||
}
|
||||
70
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/gke.go
generated
vendored
Normal file
70
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/gke.go
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 gcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// If the kubernetes.default.svc service exists in the cluster,
|
||||
// then the KUBERNETES_SERVICE_HOST env var will be populated.
|
||||
// Use this as an indication that we are running on kubernetes.
|
||||
k8sServiceHostEnv = "KUBERNETES_SERVICE_HOST"
|
||||
// See the available GKE metadata:
|
||||
// https://cloud.google.com/kubernetes-engine/docs/concepts/workload-identity#instance_metadata
|
||||
clusterNameMetadataAttr = "cluster-name"
|
||||
clusterLocationMetadataAttr = "cluster-location"
|
||||
)
|
||||
|
||||
func (d *Detector) onGKE() bool {
|
||||
_, found := d.os.LookupEnv(k8sServiceHostEnv)
|
||||
return found
|
||||
}
|
||||
|
||||
// GKEHostID returns the instance ID of the instance on which this program is running.
|
||||
func (d *Detector) GKEHostID() (string, error) {
|
||||
return d.GCEHostID()
|
||||
}
|
||||
|
||||
// GKEClusterName returns the name if the GKE cluster in which this program is running.
|
||||
func (d *Detector) GKEClusterName() (string, error) {
|
||||
return d.metadata.InstanceAttributeValue(clusterNameMetadataAttr)
|
||||
}
|
||||
|
||||
type LocationType int64
|
||||
|
||||
const (
|
||||
UndefinedLocation LocationType = iota
|
||||
Zone
|
||||
Region
|
||||
)
|
||||
|
||||
// GKEAvailabilityZoneOrRegion returns the location of the cluster and whether the cluster is zonal or regional.
|
||||
func (d *Detector) GKEAvailabilityZoneOrRegion() (string, LocationType, error) {
|
||||
clusterLocation, err := d.metadata.InstanceAttributeValue(clusterLocationMetadataAttr)
|
||||
if err != nil {
|
||||
return "", UndefinedLocation, err
|
||||
}
|
||||
switch strings.Count(clusterLocation, "-") {
|
||||
case 1:
|
||||
return clusterLocation, Region, nil
|
||||
case 2:
|
||||
return clusterLocation, Zone, nil
|
||||
default:
|
||||
return "", UndefinedLocation, fmt.Errorf("unrecognized format for cluster location: %v", clusterLocation)
|
||||
}
|
||||
}
|
||||
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/LICENSE
generated
vendored
Normal file
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
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.
|
||||
37
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/README.md
generated
vendored
Normal file
37
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# OpenTelemetry Google Cloud Monitoring Exporter
|
||||
|
||||
[](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric)
|
||||
[![Apache License][license-image]][license-url]
|
||||
|
||||
OpenTelemetry Google Cloud Monitoring Exporter allow the user to send collected metrics to Google Cloud.
|
||||
|
||||
[Google Cloud Monitoring](https://cloud.google.com/monitoring) provides visibility into the performance, uptime, and overall health of cloud-powered applications. It collects metrics, events, and metadata from Google Cloud, Amazon Web Services, hosted uptime probes, application instrumentation, and a variety of common application components including Cassandra, Nginx, Apache Web Server, Elasticsearch, and many others. Operations ingests that data and generates insights via dashboards, charts, and alerts. Cloud Monitoring alerting helps you collaborate by integrating with Slack, PagerDuty, and more.
|
||||
|
||||
## Setup
|
||||
|
||||
Google Cloud Monitoring is a managed service provided by Google Cloud Platform. Google Cloud Monitoring requires to set up "Workspace" in advance. The guide to create a new Workspace is available on [the official document](https://cloud.google.com/monitoring/workspaces/create).
|
||||
|
||||
## Authentication
|
||||
|
||||
The Google Cloud Monitoring exporter depends upon [`google.FindDefaultCredentials`](https://pkg.go.dev/golang.org/x/oauth2/google?tab=doc#FindDefaultCredentials), so the service account is automatically detected by default, but also the custom credential file (so called `service_account_key.json`) can be detected with specific conditions. Quoting from the document of `google.FindDefaultCredentials`:
|
||||
|
||||
* A JSON file whose path is specified by the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
|
||||
* A JSON file in a location known to the gcloud command-line tool. On Windows, this is `%APPDATA%/gcloud/application_default_credentials.json`. On other systems, `$HOME/.config/gcloud/application_default_credentials.json`.
|
||||
|
||||
When running code locally, you may need to specify a Google Project ID in addition to `GOOGLE_APPLICATION_CREDENTIALS`. This is best done using an environment variable (e.g. `GOOGLE_CLOUD_PROJECT`) and the `metric.WithProjectID` method, e.g.:
|
||||
|
||||
```golang
|
||||
projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
|
||||
opts := []mexporter.Option{
|
||||
mexporter.WithProjectID(projectID),
|
||||
}
|
||||
```
|
||||
|
||||
## Useful links
|
||||
|
||||
* For more information on OpenTelemetry, visit: https://opentelemetry.io/
|
||||
* For more about OpenTelemetry Go, visit: https://github.com/open-telemetry/opentelemetry-go
|
||||
* Learn more about Google Cloud Monitoring at https://cloud.google.com/monitoring
|
||||
|
||||
[license-url]: https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/main/LICENSE
|
||||
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
|
||||
49
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/cloudmonitoring.go
generated
vendored
Normal file
49
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/cloudmonitoring.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
|
||||
|
||||
monitoring "cloud.google.com/go/monitoring/apiv3/v2"
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
// New creates a new Exporter thats implements metric.Exporter.
|
||||
func New(opts ...Option) (sdkmetric.Exporter, error) {
|
||||
o := options{
|
||||
context: context.Background(),
|
||||
resourceAttributeFilter: DefaultResourceAttributesFilter,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&o)
|
||||
}
|
||||
|
||||
if o.projectID == "" {
|
||||
creds, err := google.FindDefaultCredentials(o.context, monitoring.DefaultAuthScopes()...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find Google Cloud credentials: %v", err)
|
||||
}
|
||||
if creds.ProjectID == "" {
|
||||
return nil, errors.New("google cloud monitoring: no project found with application default credentials")
|
||||
}
|
||||
o.projectID = creds.ProjectID
|
||||
}
|
||||
return newMetricExporter(&o)
|
||||
}
|
||||
97
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/constants.go
generated
vendored
Normal file
97
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/constants.go
generated
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
// TODO: remove this file when the constants are ready in the Go SDK
|
||||
|
||||
// Mappings for the well-known OpenTelemetry resource label keys
|
||||
// to applicable Monitored Resource label keys.
|
||||
// A uniquely identifying name for the Kubernetes cluster. Kubernetes
|
||||
// does not have cluster names as an internal concept so this may be
|
||||
// set to any meaningful value within the environment. For example,
|
||||
// GKE clusters have a name which can be used for this label.
|
||||
const (
|
||||
// Deprecated: use semconv.CloudProviderKey instead.
|
||||
CloudKeyProvider = "cloud.provider"
|
||||
// Deprecated: use semconv.CloudAccountIDKey instead.
|
||||
CloudKeyAccountID = "cloud.account.id"
|
||||
// Deprecated: use semconv.CloudRegionKey instead.
|
||||
CloudKeyRegion = "cloud.region"
|
||||
// Deprecated: use semconv.CloudAvailabilityZoneKey instead.
|
||||
CloudKeyZone = "cloud.availability_zone"
|
||||
|
||||
// Deprecated: use semconv.ServiceNamespaceKey instead.
|
||||
ServiceKeyNamespace = "service.namespace"
|
||||
// Deprecated: use semconv.ServiceInstanceIDKey instead.
|
||||
ServiceKeyInstanceID = "service.instance.id"
|
||||
// Deprecated: use semconv.ServiceNameKey instead.
|
||||
ServiceKeyName = "service.name"
|
||||
|
||||
// Deprecated: HostType is not needed.
|
||||
HostType = "host"
|
||||
// A uniquely identifying name for the host.
|
||||
// Deprecated: use semconv.HostNameKey instead.
|
||||
HostKeyName = "host.name"
|
||||
// A hostname as returned by the 'hostname' command on host machine.
|
||||
// Deprecated: HostKeyHostName is not needed.
|
||||
HostKeyHostName = "host.hostname"
|
||||
// Deprecated: use semconv.HostIDKey instead.
|
||||
HostKeyID = "host.id"
|
||||
// Deprecated: use semconv.HostTypeKey instead.
|
||||
HostKeyType = "host.type"
|
||||
|
||||
// A uniquely identifying name for the Container.
|
||||
// Deprecated: use semconv.ContainerNameKey instead.
|
||||
ContainerKeyName = "container.name"
|
||||
// Deprecated: use semconv.ContainerImageNameKey instead.
|
||||
ContainerKeyImageName = "container.image.name"
|
||||
// Deprecated: use semconv.ContainerImageTagKey instead.
|
||||
ContainerKeyImageTag = "container.image.tag"
|
||||
|
||||
// Cloud Providers
|
||||
// Deprecated: use semconv.CloudProviderAWS instead.
|
||||
CloudProviderAWS = "aws"
|
||||
// Deprecated: use semconv.CloudProviderGCP instead.
|
||||
CloudProviderGCP = "gcp"
|
||||
// Deprecated: use semconv.CloudProviderAzure instead.
|
||||
CloudProviderAZURE = "azure"
|
||||
|
||||
// Deprecated: Use "k8s" instead. This should not be needed.
|
||||
K8S = "k8s"
|
||||
// Deprecated: use semconv.K8SClusterNameKey instead.
|
||||
K8SKeyClusterName = "k8s.cluster.name"
|
||||
// Deprecated: use semconv.K8SNamespaceNameKey instead.
|
||||
K8SKeyNamespaceName = "k8s.namespace.name"
|
||||
// Deprecated: use semconv.K8SPodNameKey instead.
|
||||
K8SKeyPodName = "k8s.pod.name"
|
||||
// Deprecated: use semconv.K8SDeploymentNameKey instead.
|
||||
K8SKeyDeploymentName = "k8s.deployment.name"
|
||||
|
||||
// Monitored Resources types
|
||||
// Deprecated: Use "k8s_container" instead.
|
||||
K8SContainer = "k8s_container"
|
||||
// Deprecated: Use "k8s_node" instead.
|
||||
K8SNode = "k8s_node"
|
||||
// Deprecated: Use "k8s_pod" instead.
|
||||
K8SPod = "k8s_pod"
|
||||
// Deprecated: Use "k8s_cluster" instead.
|
||||
K8SCluster = "k8s_cluster"
|
||||
// Deprecated: Use "gce_instance" instead.
|
||||
GCEInstance = "gce_instance"
|
||||
// Deprecated: Use "aws_ec2_instance" instead.
|
||||
AWSEC2Instance = "aws_ec2_instance"
|
||||
// Deprecated: Use "generic_task" instead.
|
||||
GenericTask = "generic_task"
|
||||
)
|
||||
32
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/error.go
generated
vendored
Normal file
32
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
errBlankProjectID = errors.New("expecting a non-blank ProjectID")
|
||||
)
|
||||
|
||||
type errUnexpectedAggregationKind struct {
|
||||
kind string
|
||||
}
|
||||
|
||||
func (e errUnexpectedAggregationKind) Error() string {
|
||||
return fmt.Sprintf("the metric kind is unexpected: %v", e.kind)
|
||||
}
|
||||
890
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/metric.go
generated
vendored
Normal file
890
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/metric.go
generated
vendored
Normal file
|
|
@ -0,0 +1,890 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
monitoring "cloud.google.com/go/monitoring/apiv3/v2"
|
||||
"cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/genproto/googleapis/api/distribution"
|
||||
"google.golang.org/genproto/googleapis/api/label"
|
||||
googlemetricpb "google.golang.org/genproto/googleapis/api/metric"
|
||||
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding/gzip"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping"
|
||||
)
|
||||
|
||||
const (
|
||||
// The number of timeserieses to send to GCM in a single request. This
|
||||
// is a hard limit in the GCM API, so we never want to exceed 200.
|
||||
sendBatchSize = 200
|
||||
|
||||
cloudMonitoringMetricDescriptorNameFormat = "workload.googleapis.com/%s"
|
||||
platformMappingMonitoredResourceKey = "gcp.resource_type"
|
||||
)
|
||||
|
||||
// key is used to judge the uniqueness of the record descriptor.
|
||||
type key struct {
|
||||
name string
|
||||
libraryname string
|
||||
}
|
||||
|
||||
func keyOf(metrics metricdata.Metrics, library instrumentation.Library) key {
|
||||
return key{
|
||||
name: metrics.Name,
|
||||
libraryname: library.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// metricExporter is the implementation of OpenTelemetry metric exporter for
|
||||
// Google Cloud Monitoring.
|
||||
type metricExporter struct {
|
||||
o *options
|
||||
shutdown chan struct{}
|
||||
// mdCache is the cache to hold MetricDescriptor to avoid creating duplicate MD.
|
||||
mdCache map[key]*googlemetricpb.MetricDescriptor
|
||||
client *monitoring.MetricClient
|
||||
mdLock sync.RWMutex
|
||||
shutdownOnce sync.Once
|
||||
}
|
||||
|
||||
// ForceFlush does nothing, the exporter holds no state.
|
||||
func (e *metricExporter) ForceFlush(ctx context.Context) error { return ctx.Err() }
|
||||
|
||||
// Shutdown shuts down the client connections.
|
||||
func (e *metricExporter) Shutdown(ctx context.Context) error {
|
||||
err := errShutdown
|
||||
e.shutdownOnce.Do(func() {
|
||||
close(e.shutdown)
|
||||
err = errors.Join(ctx.Err(), e.client.Close())
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// newMetricExporter returns an exporter that uploads OTel metric data to Google Cloud Monitoring.
|
||||
func newMetricExporter(o *options) (*metricExporter, error) {
|
||||
if strings.TrimSpace(o.projectID) == "" {
|
||||
return nil, errBlankProjectID
|
||||
}
|
||||
|
||||
clientOpts := append([]option.ClientOption{option.WithGRPCDialOption(grpc.WithUserAgent(userAgent))}, o.monitoringClientOptions...)
|
||||
ctx := o.context
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
client, err := monitoring.NewMetricClient(ctx, clientOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.compression == "gzip" {
|
||||
client.CallOptions.GetMetricDescriptor = append(client.CallOptions.GetMetricDescriptor,
|
||||
gax.WithGRPCOptions(grpc.UseCompressor(gzip.Name)))
|
||||
client.CallOptions.CreateMetricDescriptor = append(client.CallOptions.CreateMetricDescriptor,
|
||||
gax.WithGRPCOptions(grpc.UseCompressor(gzip.Name)))
|
||||
client.CallOptions.CreateTimeSeries = append(client.CallOptions.CreateTimeSeries,
|
||||
gax.WithGRPCOptions(grpc.UseCompressor(gzip.Name)))
|
||||
client.CallOptions.CreateServiceTimeSeries = append(client.CallOptions.CreateServiceTimeSeries,
|
||||
gax.WithGRPCOptions(grpc.UseCompressor(gzip.Name)))
|
||||
}
|
||||
|
||||
cache := map[key]*googlemetricpb.MetricDescriptor{}
|
||||
e := &metricExporter{
|
||||
o: o,
|
||||
mdCache: cache,
|
||||
client: client,
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
var errShutdown = fmt.Errorf("exporter is shutdown")
|
||||
|
||||
// Export exports OpenTelemetry Metrics to Google Cloud Monitoring.
|
||||
func (me *metricExporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error {
|
||||
select {
|
||||
case <-me.shutdown:
|
||||
return errShutdown
|
||||
default:
|
||||
}
|
||||
|
||||
if me.o.destinationProjectQuota {
|
||||
ctx = metadata.NewOutgoingContext(ctx, metadata.New(map[string]string{"x-goog-user-project": strings.TrimPrefix(me.o.projectID, "projects/")}))
|
||||
}
|
||||
return errors.Join(
|
||||
me.exportMetricDescriptor(ctx, rm),
|
||||
me.exportTimeSeries(ctx, rm),
|
||||
)
|
||||
}
|
||||
|
||||
// Temporality returns the Temporality to use for an instrument kind.
|
||||
func (me *metricExporter) Temporality(ik metric.InstrumentKind) metricdata.Temporality {
|
||||
return metric.DefaultTemporalitySelector(ik)
|
||||
}
|
||||
|
||||
// Aggregation returns the Aggregation to use for an instrument kind.
|
||||
func (me *metricExporter) Aggregation(ik metric.InstrumentKind) metric.Aggregation {
|
||||
return metric.DefaultAggregationSelector(ik)
|
||||
}
|
||||
|
||||
// exportMetricDescriptor create MetricDescriptor from the record
|
||||
// if the descriptor is not registered in Cloud Monitoring yet.
|
||||
func (me *metricExporter) exportMetricDescriptor(ctx context.Context, rm *metricdata.ResourceMetrics) error {
|
||||
// We only send metric descriptors if we're configured *and* we're not sending service timeseries.
|
||||
if me.o.disableCreateMetricDescriptors {
|
||||
return nil
|
||||
}
|
||||
|
||||
me.mdLock.Lock()
|
||||
defer me.mdLock.Unlock()
|
||||
mds := make(map[key]*googlemetricpb.MetricDescriptor)
|
||||
extraLabels := me.extraLabelsFromResource(rm.Resource)
|
||||
for _, scope := range rm.ScopeMetrics {
|
||||
for _, metrics := range scope.Metrics {
|
||||
k := keyOf(metrics, scope.Scope)
|
||||
|
||||
if _, ok := me.mdCache[k]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, localok := mds[k]; !localok {
|
||||
md := me.recordToMdpb(metrics, extraLabels)
|
||||
mds[k] = md
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This process is synchronous and blocks longer time if records in cps
|
||||
// have many different descriptors. In the cps.ForEach above, it should spawn
|
||||
// goroutines to send CreateMetricDescriptorRequest asynchronously in the case
|
||||
// the descriptor does not exist in global cache (me.mdCache).
|
||||
// See details in #26.
|
||||
var errs []error
|
||||
for kmd, md := range mds {
|
||||
err := me.createMetricDescriptorIfNeeded(ctx, md)
|
||||
if err == nil {
|
||||
me.mdCache[kmd] = md
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (me *metricExporter) createMetricDescriptorIfNeeded(ctx context.Context, md *googlemetricpb.MetricDescriptor) error {
|
||||
mdReq := &monitoringpb.GetMetricDescriptorRequest{
|
||||
Name: fmt.Sprintf("projects/%s/metricDescriptors/%s", me.o.projectID, md.Type),
|
||||
}
|
||||
_, err := me.client.GetMetricDescriptor(ctx, mdReq)
|
||||
if err == nil {
|
||||
// If the metric descriptor already exists, skip the CreateMetricDescriptor call.
|
||||
// Metric descriptors cannot be updated without deleting them first, so there
|
||||
// isn't anything we can do here:
|
||||
// https://cloud.google.com/monitoring/custom-metrics/creating-metrics#md-modify
|
||||
return nil
|
||||
}
|
||||
req := &monitoringpb.CreateMetricDescriptorRequest{
|
||||
Name: fmt.Sprintf("projects/%s", me.o.projectID),
|
||||
MetricDescriptor: md,
|
||||
}
|
||||
_, err = me.client.CreateMetricDescriptor(ctx, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// exportTimeSeries create TimeSeries from the records in cps.
|
||||
// res should be the common resource among all TimeSeries, such as instance id, application name and so on.
|
||||
func (me *metricExporter) exportTimeSeries(ctx context.Context, rm *metricdata.ResourceMetrics) error {
|
||||
tss, err := me.recordsToTspbs(rm)
|
||||
if len(tss) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("projects/%s", me.o.projectID)
|
||||
|
||||
errs := []error{err}
|
||||
for i := 0; i < len(tss); i += sendBatchSize {
|
||||
j := i + sendBatchSize
|
||||
if j >= len(tss) {
|
||||
j = len(tss)
|
||||
}
|
||||
|
||||
// TODO: When this exporter is rewritten, support writing to multiple
|
||||
// projects based on the "gcp.project.id" resource.
|
||||
req := &monitoringpb.CreateTimeSeriesRequest{
|
||||
Name: name,
|
||||
TimeSeries: tss[i:j],
|
||||
}
|
||||
if me.o.createServiceTimeSeries {
|
||||
errs = append(errs, me.client.CreateServiceTimeSeries(ctx, req))
|
||||
} else {
|
||||
errs = append(errs, me.client.CreateTimeSeries(ctx, req))
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (me *metricExporter) extraLabelsFromResource(res *resource.Resource) *attribute.Set {
|
||||
set, _ := attribute.NewSetWithFiltered(res.Attributes(), me.o.resourceAttributeFilter)
|
||||
return &set
|
||||
}
|
||||
|
||||
// descToMetricType converts descriptor to MetricType proto type.
|
||||
// Basically this returns default value ("workload.googleapis.com/[metric type]").
|
||||
func (me *metricExporter) descToMetricType(desc metricdata.Metrics) string {
|
||||
if formatter := me.o.metricDescriptorTypeFormatter; formatter != nil {
|
||||
return formatter(desc)
|
||||
}
|
||||
return fmt.Sprintf(cloudMonitoringMetricDescriptorNameFormat, desc.Name)
|
||||
}
|
||||
|
||||
// metricTypeToDisplayName takes a GCM metric type, like (workload.googleapis.com/MyCoolMetric) and returns the display name.
|
||||
func metricTypeToDisplayName(mURL string) string {
|
||||
// strip domain, keep path after domain.
|
||||
u, err := url.Parse(fmt.Sprintf("metrics://%s", mURL))
|
||||
if err != nil || u.Path == "" {
|
||||
return mURL
|
||||
}
|
||||
return strings.TrimLeft(u.Path, "/")
|
||||
}
|
||||
|
||||
// recordToMdpb extracts data and converts them to googlemetricpb.MetricDescriptor.
|
||||
func (me *metricExporter) recordToMdpb(metrics metricdata.Metrics, extraLabels *attribute.Set) *googlemetricpb.MetricDescriptor {
|
||||
name := metrics.Name
|
||||
typ := me.descToMetricType(metrics)
|
||||
kind, valueType := recordToMdpbKindType(metrics.Data)
|
||||
|
||||
// Detailed explanations on MetricDescriptor proto is not documented on
|
||||
// generated Go packages. Refer to the original proto file.
|
||||
// https://github.com/googleapis/googleapis/blob/50af053/google/api/metric.proto#L33
|
||||
return &googlemetricpb.MetricDescriptor{
|
||||
Name: name,
|
||||
DisplayName: metricTypeToDisplayName(typ),
|
||||
Type: typ,
|
||||
MetricKind: kind,
|
||||
ValueType: valueType,
|
||||
Unit: string(metrics.Unit),
|
||||
Description: metrics.Description,
|
||||
Labels: labelDescriptors(metrics, extraLabels),
|
||||
}
|
||||
}
|
||||
|
||||
func labelDescriptors(metrics metricdata.Metrics, extraLabels *attribute.Set) []*label.LabelDescriptor {
|
||||
labels := []*label.LabelDescriptor{}
|
||||
seenKeys := map[string]struct{}{}
|
||||
addAttributes := func(attr *attribute.Set) {
|
||||
iter := attr.Iter()
|
||||
for iter.Next() {
|
||||
kv := iter.Attribute()
|
||||
// Skip keys that have already been set
|
||||
if _, ok := seenKeys[normalizeLabelKey(string(kv.Key))]; ok {
|
||||
continue
|
||||
}
|
||||
labels = append(labels, &label.LabelDescriptor{
|
||||
Key: normalizeLabelKey(string(kv.Key)),
|
||||
})
|
||||
seenKeys[normalizeLabelKey(string(kv.Key))] = struct{}{}
|
||||
}
|
||||
}
|
||||
addAttributes(extraLabels)
|
||||
switch a := metrics.Data.(type) {
|
||||
case metricdata.Gauge[int64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
case metricdata.Gauge[float64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
case metricdata.Sum[int64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
case metricdata.Sum[float64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
case metricdata.Histogram[float64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
case metricdata.Histogram[int64]:
|
||||
for _, pt := range a.DataPoints {
|
||||
addAttributes(&pt.Attributes)
|
||||
}
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
type attributes struct {
|
||||
attrs attribute.Set
|
||||
}
|
||||
|
||||
func (attrs *attributes) GetString(key string) (string, bool) {
|
||||
value, ok := attrs.attrs.Value(attribute.Key(key))
|
||||
return value.AsString(), ok
|
||||
}
|
||||
|
||||
// resourceToMonitoredResourcepb converts resource in OTel to MonitoredResource
|
||||
// proto type for Cloud Monitoring.
|
||||
//
|
||||
// https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.monitoredResourceDescriptors
|
||||
func (me *metricExporter) resourceToMonitoredResourcepb(res *resource.Resource) *monitoredrespb.MonitoredResource {
|
||||
platformMrType, platformMappingRequested := res.Set().Value(platformMappingMonitoredResourceKey)
|
||||
|
||||
// check if platform mapping is requested and possible
|
||||
if platformMappingRequested && platformMrType.AsString() == me.o.monitoredResourceDescription.mrType {
|
||||
// assemble attributes required to construct this MR
|
||||
attributeMap := make(map[string]string)
|
||||
for expectedLabel := range me.o.monitoredResourceDescription.mrLabels {
|
||||
value, found := res.Set().Value(attribute.Key(expectedLabel))
|
||||
if found {
|
||||
attributeMap[expectedLabel] = value.AsString()
|
||||
}
|
||||
}
|
||||
return &monitoredrespb.MonitoredResource{
|
||||
Type: platformMrType.AsString(),
|
||||
Labels: attributeMap,
|
||||
}
|
||||
}
|
||||
|
||||
gmr := resourcemapping.ResourceAttributesToMonitoringMonitoredResource(&attributes{
|
||||
attrs: attribute.NewSet(res.Attributes()...),
|
||||
})
|
||||
newLabels := make(map[string]string, len(gmr.Labels))
|
||||
for k, v := range gmr.Labels {
|
||||
newLabels[k] = sanitizeUTF8(v)
|
||||
}
|
||||
mr := &monitoredrespb.MonitoredResource{
|
||||
Type: gmr.Type,
|
||||
Labels: newLabels,
|
||||
}
|
||||
return mr
|
||||
}
|
||||
|
||||
// recordToMdpbKindType return the mapping from OTel's record descriptor to
|
||||
// Cloud Monitoring's MetricKind and ValueType.
|
||||
func recordToMdpbKindType(a metricdata.Aggregation) (googlemetricpb.MetricDescriptor_MetricKind, googlemetricpb.MetricDescriptor_ValueType) {
|
||||
switch agg := a.(type) {
|
||||
case metricdata.Gauge[int64]:
|
||||
return googlemetricpb.MetricDescriptor_GAUGE, googlemetricpb.MetricDescriptor_INT64
|
||||
case metricdata.Gauge[float64]:
|
||||
return googlemetricpb.MetricDescriptor_GAUGE, googlemetricpb.MetricDescriptor_DOUBLE
|
||||
case metricdata.Sum[int64]:
|
||||
if agg.IsMonotonic {
|
||||
return googlemetricpb.MetricDescriptor_CUMULATIVE, googlemetricpb.MetricDescriptor_INT64
|
||||
}
|
||||
return googlemetricpb.MetricDescriptor_GAUGE, googlemetricpb.MetricDescriptor_INT64
|
||||
case metricdata.Sum[float64]:
|
||||
if agg.IsMonotonic {
|
||||
return googlemetricpb.MetricDescriptor_CUMULATIVE, googlemetricpb.MetricDescriptor_DOUBLE
|
||||
}
|
||||
return googlemetricpb.MetricDescriptor_GAUGE, googlemetricpb.MetricDescriptor_DOUBLE
|
||||
case metricdata.Histogram[int64], metricdata.Histogram[float64]:
|
||||
return googlemetricpb.MetricDescriptor_CUMULATIVE, googlemetricpb.MetricDescriptor_DISTRIBUTION
|
||||
default:
|
||||
return googlemetricpb.MetricDescriptor_METRIC_KIND_UNSPECIFIED, googlemetricpb.MetricDescriptor_VALUE_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
// recordToMpb converts data from records to Metric proto type for Cloud Monitoring.
|
||||
func (me *metricExporter) recordToMpb(metrics metricdata.Metrics, attributes attribute.Set, library instrumentation.Library, extraLabels *attribute.Set) *googlemetricpb.Metric {
|
||||
me.mdLock.RLock()
|
||||
defer me.mdLock.RUnlock()
|
||||
k := keyOf(metrics, library)
|
||||
md, ok := me.mdCache[k]
|
||||
if !ok {
|
||||
md = me.recordToMdpb(metrics, extraLabels)
|
||||
}
|
||||
|
||||
labels := make(map[string]string)
|
||||
addAttributes := func(attr *attribute.Set) {
|
||||
iter := attr.Iter()
|
||||
for iter.Next() {
|
||||
kv := iter.Attribute()
|
||||
labels[normalizeLabelKey(string(kv.Key))] = sanitizeUTF8(kv.Value.Emit())
|
||||
}
|
||||
}
|
||||
addAttributes(extraLabels)
|
||||
addAttributes(&attributes)
|
||||
|
||||
return &googlemetricpb.Metric{
|
||||
Type: md.Type,
|
||||
Labels: labels,
|
||||
}
|
||||
}
|
||||
|
||||
// recordToTspb converts record to TimeSeries proto type with common resource.
|
||||
// ref. https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TimeSeries
|
||||
func (me *metricExporter) recordToTspb(m metricdata.Metrics, mr *monitoredrespb.MonitoredResource, library instrumentation.Scope, extraLabels *attribute.Set) ([]*monitoringpb.TimeSeries, error) {
|
||||
var tss []*monitoringpb.TimeSeries
|
||||
var errs []error
|
||||
if m.Data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch a := m.Data.(type) {
|
||||
case metricdata.Gauge[int64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := gaugeToTimeSeries[int64](point, m, mr)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.Gauge[float64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := gaugeToTimeSeries[float64](point, m, mr)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.Sum[int64]:
|
||||
for _, point := range a.DataPoints {
|
||||
var ts *monitoringpb.TimeSeries
|
||||
var err error
|
||||
if a.IsMonotonic {
|
||||
ts, err = sumToTimeSeries[int64](point, m, mr)
|
||||
} else {
|
||||
// Send non-monotonic sums as gauges
|
||||
ts, err = gaugeToTimeSeries[int64](point, m, mr)
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.Sum[float64]:
|
||||
for _, point := range a.DataPoints {
|
||||
var ts *monitoringpb.TimeSeries
|
||||
var err error
|
||||
if a.IsMonotonic {
|
||||
ts, err = sumToTimeSeries[float64](point, m, mr)
|
||||
} else {
|
||||
// Send non-monotonic sums as gauges
|
||||
ts, err = gaugeToTimeSeries[float64](point, m, mr)
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.Histogram[int64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := histogramToTimeSeries(point, m, mr, me.o.enableSumOfSquaredDeviation, me.o.projectID)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.Histogram[float64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := histogramToTimeSeries(point, m, mr, me.o.enableSumOfSquaredDeviation, me.o.projectID)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.ExponentialHistogram[int64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := expHistogramToTimeSeries(point, m, mr, me.o.enableSumOfSquaredDeviation, me.o.projectID)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
case metricdata.ExponentialHistogram[float64]:
|
||||
for _, point := range a.DataPoints {
|
||||
ts, err := expHistogramToTimeSeries(point, m, mr, me.o.enableSumOfSquaredDeviation, me.o.projectID)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
ts.Metric = me.recordToMpb(m, point.Attributes, library, extraLabels)
|
||||
tss = append(tss, ts)
|
||||
}
|
||||
default:
|
||||
errs = append(errs, errUnexpectedAggregationKind{kind: reflect.TypeOf(m.Data).String()})
|
||||
}
|
||||
return tss, errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (me *metricExporter) recordsToTspbs(rm *metricdata.ResourceMetrics) ([]*monitoringpb.TimeSeries, error) {
|
||||
mr := me.resourceToMonitoredResourcepb(rm.Resource)
|
||||
extraLabels := me.extraLabelsFromResource(rm.Resource)
|
||||
|
||||
var (
|
||||
tss []*monitoringpb.TimeSeries
|
||||
errs []error
|
||||
)
|
||||
for _, scope := range rm.ScopeMetrics {
|
||||
for _, metrics := range scope.Metrics {
|
||||
ts, err := me.recordToTspb(metrics, mr, scope.Scope, extraLabels)
|
||||
errs = append(errs, err)
|
||||
tss = append(tss, ts...)
|
||||
}
|
||||
}
|
||||
|
||||
return tss, errors.Join(errs...)
|
||||
}
|
||||
|
||||
func sanitizeUTF8(s string) string {
|
||||
return strings.ToValidUTF8(s, "<22>")
|
||||
}
|
||||
|
||||
func gaugeToTimeSeries[N int64 | float64](point metricdata.DataPoint[N], metrics metricdata.Metrics, mr *monitoredrespb.MonitoredResource) (*monitoringpb.TimeSeries, error) {
|
||||
value, valueType := numberDataPointToValue(point)
|
||||
timestamp := timestamppb.New(point.Time)
|
||||
if err := timestamp.CheckValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &monitoringpb.TimeSeries{
|
||||
Resource: mr,
|
||||
Unit: string(metrics.Unit),
|
||||
MetricKind: googlemetricpb.MetricDescriptor_GAUGE,
|
||||
ValueType: valueType,
|
||||
Points: []*monitoringpb.Point{{
|
||||
Interval: &monitoringpb.TimeInterval{
|
||||
EndTime: timestamp,
|
||||
},
|
||||
Value: value,
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func sumToTimeSeries[N int64 | float64](point metricdata.DataPoint[N], metrics metricdata.Metrics, mr *monitoredrespb.MonitoredResource) (*monitoringpb.TimeSeries, error) {
|
||||
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value, valueType := numberDataPointToValue[N](point)
|
||||
return &monitoringpb.TimeSeries{
|
||||
Resource: mr,
|
||||
Unit: string(metrics.Unit),
|
||||
MetricKind: googlemetricpb.MetricDescriptor_CUMULATIVE,
|
||||
ValueType: valueType,
|
||||
Points: []*monitoringpb.Point{{
|
||||
Interval: interval,
|
||||
Value: value,
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO(@dashpole): Refactor to pass control-coupling lint check.
|
||||
//
|
||||
//nolint:revive
|
||||
func histogramToTimeSeries[N int64 | float64](point metricdata.HistogramDataPoint[N], metrics metricdata.Metrics, mr *monitoredrespb.MonitoredResource, enableSOSD bool, projectID string) (*monitoringpb.TimeSeries, error) {
|
||||
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
distributionValue := histToDistribution(point, projectID)
|
||||
if enableSOSD {
|
||||
setSumOfSquaredDeviation(point, distributionValue)
|
||||
}
|
||||
return &monitoringpb.TimeSeries{
|
||||
Resource: mr,
|
||||
Unit: string(metrics.Unit),
|
||||
MetricKind: googlemetricpb.MetricDescriptor_CUMULATIVE,
|
||||
ValueType: googlemetricpb.MetricDescriptor_DISTRIBUTION,
|
||||
Points: []*monitoringpb.Point{{
|
||||
Interval: interval,
|
||||
Value: &monitoringpb.TypedValue{
|
||||
Value: &monitoringpb.TypedValue_DistributionValue{
|
||||
DistributionValue: distributionValue,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func expHistogramToTimeSeries[N int64 | float64](point metricdata.ExponentialHistogramDataPoint[N], metrics metricdata.Metrics, mr *monitoredrespb.MonitoredResource, enableSOSD bool, projectID string) (*monitoringpb.TimeSeries, error) {
|
||||
interval, err := toNonemptyTimeIntervalpb(point.StartTime, point.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
distributionValue := expHistToDistribution(point, projectID)
|
||||
// TODO: Implement "setSumOfSquaredDeviationExpHist" for parameter "enableSOSD" functionality.
|
||||
return &monitoringpb.TimeSeries{
|
||||
Resource: mr,
|
||||
Unit: string(metrics.Unit),
|
||||
MetricKind: googlemetricpb.MetricDescriptor_CUMULATIVE,
|
||||
ValueType: googlemetricpb.MetricDescriptor_DISTRIBUTION,
|
||||
Points: []*monitoringpb.Point{{
|
||||
Interval: interval,
|
||||
Value: &monitoringpb.TypedValue{
|
||||
Value: &monitoringpb.TypedValue_DistributionValue{
|
||||
DistributionValue: distributionValue,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toNonemptyTimeIntervalpb(start, end time.Time) (*monitoringpb.TimeInterval, error) {
|
||||
// The end time of a new interval must be at least a millisecond after the end time of the
|
||||
// previous interval, for all non-gauge types.
|
||||
// https://cloud.google.com/monitoring/api/ref_v3/rpc/google.monitoring.v3#timeinterval
|
||||
if end.Sub(start).Milliseconds() <= 1 {
|
||||
end = start.Add(time.Millisecond)
|
||||
}
|
||||
startpb := timestamppb.New(start)
|
||||
endpb := timestamppb.New(end)
|
||||
err := errors.Join(
|
||||
startpb.CheckValid(),
|
||||
endpb.CheckValid(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &monitoringpb.TimeInterval{
|
||||
StartTime: startpb,
|
||||
EndTime: endpb,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func histToDistribution[N int64 | float64](hist metricdata.HistogramDataPoint[N], projectID string) *distribution.Distribution {
|
||||
counts := make([]int64, len(hist.BucketCounts))
|
||||
for i, v := range hist.BucketCounts {
|
||||
counts[i] = int64(v)
|
||||
}
|
||||
var mean float64
|
||||
if !math.IsNaN(float64(hist.Sum)) && hist.Count > 0 { // Avoid divide-by-zero
|
||||
mean = float64(hist.Sum) / float64(hist.Count)
|
||||
}
|
||||
return &distribution.Distribution{
|
||||
Count: int64(hist.Count),
|
||||
Mean: mean,
|
||||
BucketCounts: counts,
|
||||
BucketOptions: &distribution.Distribution_BucketOptions{
|
||||
Options: &distribution.Distribution_BucketOptions_ExplicitBuckets{
|
||||
ExplicitBuckets: &distribution.Distribution_BucketOptions_Explicit{
|
||||
Bounds: hist.Bounds,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exemplars: toDistributionExemplar[N](hist.Exemplars, projectID),
|
||||
}
|
||||
}
|
||||
|
||||
func expHistToDistribution[N int64 | float64](hist metricdata.ExponentialHistogramDataPoint[N], projectID string) *distribution.Distribution {
|
||||
// First calculate underflow bucket with all negatives + zeros.
|
||||
underflow := hist.ZeroCount
|
||||
negativeBuckets := hist.NegativeBucket.Counts
|
||||
for i := 0; i < len(negativeBuckets); i++ {
|
||||
underflow += negativeBuckets[i]
|
||||
}
|
||||
|
||||
// Next, pull in remaining buckets.
|
||||
counts := make([]int64, len(hist.PositiveBucket.Counts)+2)
|
||||
bucketOptions := &distribution.Distribution_BucketOptions{}
|
||||
counts[0] = int64(underflow)
|
||||
positiveBuckets := hist.PositiveBucket.Counts
|
||||
for i := 0; i < len(positiveBuckets); i++ {
|
||||
counts[i+1] = int64(positiveBuckets[i])
|
||||
}
|
||||
// Overflow bucket is always empty
|
||||
counts[len(counts)-1] = 0
|
||||
|
||||
if len(hist.PositiveBucket.Counts) == 0 {
|
||||
// We cannot send exponential distributions with no positive buckets,
|
||||
// instead we send a simple overflow/underflow histogram.
|
||||
bucketOptions.Options = &distribution.Distribution_BucketOptions_ExplicitBuckets{
|
||||
ExplicitBuckets: &distribution.Distribution_BucketOptions_Explicit{
|
||||
Bounds: []float64{0},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Exponential histogram
|
||||
growth := math.Exp2(math.Exp2(-float64(hist.Scale)))
|
||||
scale := math.Pow(growth, float64(hist.PositiveBucket.Offset))
|
||||
bucketOptions.Options = &distribution.Distribution_BucketOptions_ExponentialBuckets{
|
||||
ExponentialBuckets: &distribution.Distribution_BucketOptions_Exponential{
|
||||
GrowthFactor: growth,
|
||||
Scale: scale,
|
||||
NumFiniteBuckets: int32(len(counts) - 2),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var mean float64
|
||||
if !math.IsNaN(float64(hist.Sum)) && hist.Count > 0 { // Avoid divide-by-zero
|
||||
mean = float64(hist.Sum) / float64(hist.Count)
|
||||
}
|
||||
|
||||
return &distribution.Distribution{
|
||||
Count: int64(hist.Count),
|
||||
Mean: mean,
|
||||
BucketCounts: counts,
|
||||
BucketOptions: bucketOptions,
|
||||
Exemplars: toDistributionExemplar[N](hist.Exemplars, projectID),
|
||||
}
|
||||
}
|
||||
|
||||
func toDistributionExemplar[N int64 | float64](Exemplars []metricdata.Exemplar[N], projectID string) []*distribution.Distribution_Exemplar {
|
||||
var exemplars []*distribution.Distribution_Exemplar
|
||||
for _, e := range Exemplars {
|
||||
attachments := []*anypb.Any{}
|
||||
if hasValidSpanContext(e) {
|
||||
sctx, err := anypb.New(&monitoringpb.SpanContext{
|
||||
SpanName: fmt.Sprintf("projects/%s/traces/%s/spans/%s", projectID, hex.EncodeToString(e.TraceID[:]), hex.EncodeToString(e.SpanID[:])),
|
||||
})
|
||||
if err == nil {
|
||||
attachments = append(attachments, sctx)
|
||||
}
|
||||
}
|
||||
if len(e.FilteredAttributes) > 0 {
|
||||
attr, err := anypb.New(&monitoringpb.DroppedLabels{
|
||||
Label: attributesToLabels(e.FilteredAttributes),
|
||||
})
|
||||
if err == nil {
|
||||
attachments = append(attachments, attr)
|
||||
}
|
||||
}
|
||||
exemplars = append(exemplars, &distribution.Distribution_Exemplar{
|
||||
Value: float64(e.Value),
|
||||
Timestamp: timestamppb.New(e.Time),
|
||||
Attachments: attachments,
|
||||
})
|
||||
}
|
||||
sort.Slice(exemplars, func(i, j int) bool {
|
||||
return exemplars[i].Value < exemplars[j].Value
|
||||
})
|
||||
return exemplars
|
||||
}
|
||||
|
||||
func attributesToLabels(attrs []attribute.KeyValue) map[string]string {
|
||||
labels := make(map[string]string, len(attrs))
|
||||
for _, attr := range attrs {
|
||||
labels[normalizeLabelKey(string(attr.Key))] = sanitizeUTF8(attr.Value.Emit())
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
var (
|
||||
nilTraceID trace.TraceID
|
||||
nilSpanID trace.SpanID
|
||||
)
|
||||
|
||||
func hasValidSpanContext[N int64 | float64](e metricdata.Exemplar[N]) bool {
|
||||
return !bytes.Equal(e.TraceID[:], nilTraceID[:]) && !bytes.Equal(e.SpanID[:], nilSpanID[:])
|
||||
}
|
||||
|
||||
func setSumOfSquaredDeviation[N int64 | float64](hist metricdata.HistogramDataPoint[N], dist *distribution.Distribution) {
|
||||
var prevBound float64
|
||||
// Calculate the sum of squared deviation.
|
||||
for i := 0; i < len(hist.Bounds); i++ {
|
||||
// Assume all points in the bucket occur at the middle of the bucket range
|
||||
middleOfBucket := (prevBound + hist.Bounds[i]) / 2
|
||||
dist.SumOfSquaredDeviation += float64(dist.BucketCounts[i]) * (middleOfBucket - dist.Mean) * (middleOfBucket - dist.Mean)
|
||||
prevBound = hist.Bounds[i]
|
||||
}
|
||||
// The infinity bucket is an implicit +Inf bound after the list of explicit bounds.
|
||||
// Assume points in the infinity bucket are at the top of the previous bucket
|
||||
middleOfInfBucket := prevBound
|
||||
if len(dist.BucketCounts) > 0 {
|
||||
dist.SumOfSquaredDeviation += float64(dist.BucketCounts[len(dist.BucketCounts)-1]) * (middleOfInfBucket - dist.Mean) * (middleOfInfBucket - dist.Mean)
|
||||
}
|
||||
}
|
||||
|
||||
func numberDataPointToValue[N int64 | float64](
|
||||
point metricdata.DataPoint[N],
|
||||
) (*monitoringpb.TypedValue, googlemetricpb.MetricDescriptor_ValueType) {
|
||||
switch v := any(point.Value).(type) {
|
||||
case int64:
|
||||
return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_Int64Value{
|
||||
Int64Value: v,
|
||||
}},
|
||||
googlemetricpb.MetricDescriptor_INT64
|
||||
case float64:
|
||||
return &monitoringpb.TypedValue{Value: &monitoringpb.TypedValue_DoubleValue{
|
||||
DoubleValue: v,
|
||||
}},
|
||||
googlemetricpb.MetricDescriptor_DOUBLE
|
||||
}
|
||||
// It is impossible to reach this statement
|
||||
return nil, googlemetricpb.MetricDescriptor_INT64
|
||||
}
|
||||
|
||||
// https://github.com/googleapis/googleapis/blob/c4c562f89acce603fb189679836712d08c7f8584/google/api/metric.proto#L149
|
||||
//
|
||||
// > The label key name must follow:
|
||||
// >
|
||||
// > * Only upper and lower-case letters, digits and underscores (_) are
|
||||
// > allowed.
|
||||
// > * Label name must start with a letter or digit.
|
||||
// > * The maximum length of a label name is 100 characters.
|
||||
//
|
||||
// Note: this does not truncate if a label is too long.
|
||||
func normalizeLabelKey(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
s = strings.Map(sanitizeRune, s)
|
||||
if unicode.IsDigit(rune(s[0])) {
|
||||
s = "key_" + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// converts anything that is not a letter or digit to an underscore.
|
||||
func sanitizeRune(r rune) rune {
|
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
||||
return r
|
||||
}
|
||||
// Everything else turns into an underscore
|
||||
return '_'
|
||||
}
|
||||
201
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/option.go
generated
vendored
Normal file
201
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2020-2021 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
|
||||
apioption "google.golang.org/api/option"
|
||||
)
|
||||
|
||||
var userAgent = fmt.Sprintf("opentelemetry-go %s; google-cloud-metric-exporter %s", otel.Version(), Version())
|
||||
|
||||
// MonitoredResourceDescription is the struct which holds information required to map OTel resource to specific
|
||||
// Google Cloud MonitoredResource.
|
||||
type MonitoredResourceDescription struct {
|
||||
mrLabels map[string]struct{}
|
||||
mrType string
|
||||
}
|
||||
|
||||
// Option is function type that is passed to the exporter initialization function.
|
||||
type Option func(*options)
|
||||
|
||||
// options is the struct to hold options for metricExporter and its client instance.
|
||||
type options struct {
|
||||
// context allows you to provide a custom context for API calls.
|
||||
//
|
||||
// This context will be used several times: first, to create Cloud Monitoring
|
||||
// clients, and then every time a new batch of metrics needs to be uploaded.
|
||||
//
|
||||
// If unset, context.Background() will be used.
|
||||
context context.Context
|
||||
// metricDescriptorTypeFormatter is the custom formtter for the MetricDescriptor.Type.
|
||||
// By default, the format string is "workload.googleapis.com/[metric name]".
|
||||
metricDescriptorTypeFormatter func(metricdata.Metrics) string
|
||||
// resourceAttributeFilter determinies which resource attributes to
|
||||
// add to metrics as metric labels. By default, it adds service.name,
|
||||
// service.namespace, and service.instance.id.
|
||||
resourceAttributeFilter attribute.Filter
|
||||
// monitoredResourceDescription sets whether to attempt mapping the OTel Resource to a specific
|
||||
// Google Cloud Monitored Resource. When provided, the exporter attempts to map only to the provided
|
||||
// monitored resource type.
|
||||
monitoredResourceDescription MonitoredResourceDescription
|
||||
// projectID is the identifier of the Cloud Monitoring
|
||||
// project the user is uploading the stats data to.
|
||||
// If not set, this will default to your "Application Default Credentials".
|
||||
// For details see: https://developers.google.com/accounts/docs/application-default-credentials.
|
||||
//
|
||||
// It will be used in the project_id label of a Google Cloud Monitoring monitored
|
||||
// resource if the resource does not inherently belong to a specific
|
||||
// project, e.g. on-premise resource like k8s_container or generic_task.
|
||||
projectID string
|
||||
// compression enables gzip compression on gRPC calls.
|
||||
compression string
|
||||
// monitoringClientOptions are additional options to be passed
|
||||
// to the underlying Stackdriver Monitoring API client.
|
||||
// Optional.
|
||||
monitoringClientOptions []apioption.ClientOption
|
||||
// destinationProjectQuota sets whether the request should use quota from
|
||||
// the destination project for the request.
|
||||
destinationProjectQuota bool
|
||||
|
||||
// disableCreateMetricDescriptors disables automatic MetricDescriptor creation
|
||||
disableCreateMetricDescriptors bool
|
||||
|
||||
// enableSumOfSquaredDeviation enables calculation of an estimated sum of squared
|
||||
// deviation. It isn't correct, so we don't send it by default.
|
||||
enableSumOfSquaredDeviation bool
|
||||
|
||||
// createServiceTimeSeries sets whether to create timeseries using `CreateServiceTimeSeries`.
|
||||
// Implicitly, this sets `disableCreateMetricDescriptors` to true.
|
||||
createServiceTimeSeries bool
|
||||
}
|
||||
|
||||
// WithProjectID sets Google Cloud Platform project as projectID.
|
||||
// Without using this option, it automatically detects the project ID
|
||||
// from the default credential detection process.
|
||||
// Please find the detailed order of the default credentail detection proecess on the doc:
|
||||
// https://godoc.org/golang.org/x/oauth2/google#FindDefaultCredentials
|
||||
func WithProjectID(id string) func(o *options) {
|
||||
return func(o *options) {
|
||||
o.projectID = id
|
||||
}
|
||||
}
|
||||
|
||||
// WithDestinationProjectQuota enables per-request usage of the destination
|
||||
// project's quota. For example, when setting gcp.project.id on a metric.
|
||||
func WithDestinationProjectQuota() func(o *options) {
|
||||
return func(o *options) {
|
||||
o.destinationProjectQuota = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithMonitoringClientOptions add the options for Cloud Monitoring client instance.
|
||||
// Available options are defined in.
|
||||
func WithMonitoringClientOptions(opts ...apioption.ClientOption) func(o *options) {
|
||||
return func(o *options) {
|
||||
o.monitoringClientOptions = append(o.monitoringClientOptions, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithMetricDescriptorTypeFormatter sets the custom formatter for MetricDescriptor.
|
||||
// Note that the format has to follow the convention defined in the official document.
|
||||
// The default is "workload.googleapis.com/[metric name]".
|
||||
// ref. https://cloud.google.com/monitoring/custom-metrics/creating-metrics#custom_metric_names
|
||||
func WithMetricDescriptorTypeFormatter(f func(metricdata.Metrics) string) func(o *options) {
|
||||
return func(o *options) {
|
||||
o.metricDescriptorTypeFormatter = f
|
||||
}
|
||||
}
|
||||
|
||||
// WithFilteredResourceAttributes determinies which resource attributes to
|
||||
// add to metrics as metric labels. By default, it adds service.name,
|
||||
// service.namespace, and service.instance.id. This is recommended to avoid
|
||||
// writing duplicate timeseries against the same monitored resource. Use
|
||||
// WithFilteredResourceAttributes(NoAttributes()) to disable the addition of
|
||||
// resource attributes to metric labels.
|
||||
func WithFilteredResourceAttributes(filter attribute.Filter) func(o *options) {
|
||||
return func(o *options) {
|
||||
o.resourceAttributeFilter = filter
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultResourceAttributesFilter is the default filter applied to resource
|
||||
// attributes.
|
||||
func DefaultResourceAttributesFilter(kv attribute.KeyValue) bool {
|
||||
return (kv.Key == semconv.ServiceNameKey ||
|
||||
kv.Key == semconv.ServiceNamespaceKey ||
|
||||
kv.Key == semconv.ServiceInstanceIDKey) && len(kv.Value.AsString()) > 0
|
||||
}
|
||||
|
||||
// NoAttributes can be passed to WithFilteredResourceAttributes to disable
|
||||
// adding resource attributes as metric labels.
|
||||
func NoAttributes(attribute.KeyValue) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// WithDisableCreateMetricDescriptors will disable the automatic creation of
|
||||
// MetricDescriptors when an unknown metric is set to be exported.
|
||||
func WithDisableCreateMetricDescriptors() func(o *options) {
|
||||
return func(o *options) {
|
||||
o.disableCreateMetricDescriptors = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCompression sets the compression to use for gRPC requests.
|
||||
func WithCompression(c string) func(o *options) {
|
||||
return func(o *options) {
|
||||
o.compression = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithSumOfSquaredDeviation sets the SumOfSquaredDeviation field on histograms.
|
||||
// It is an estimate, and is not the actual sum of squared deviations.
|
||||
func WithSumOfSquaredDeviation() func(o *options) {
|
||||
return func(o *options) {
|
||||
o.enableSumOfSquaredDeviation = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCreateServiceTimeSeries configures the exporter to use `CreateServiceTimeSeries` for creating timeseries.
|
||||
// If this is used, metric descriptors are not exported.
|
||||
func WithCreateServiceTimeSeries() func(o *options) {
|
||||
return func(o *options) {
|
||||
o.createServiceTimeSeries = true
|
||||
o.disableCreateMetricDescriptors = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithMonitoredResourceDescription configures the exporter to attempt to map the OpenTelemetry Resource to the provided
|
||||
// Google MonitoredResource. The provided mrLabels would be searched for in the OpenTelemetry Resource Attributes and if
|
||||
// found, would be included in the MonitoredResource labels.
|
||||
func WithMonitoredResourceDescription(mrType string, mrLabels []string) func(o *options) {
|
||||
return func(o *options) {
|
||||
mrLabelSet := make(map[string]struct{})
|
||||
for _, label := range mrLabels {
|
||||
mrLabelSet[label] = struct{}{}
|
||||
}
|
||||
o.monitoredResourceDescription = MonitoredResourceDescription{
|
||||
mrType: mrType,
|
||||
mrLabels: mrLabelSet,
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/version.go
generated
vendored
Normal file
21
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/version.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 metric
|
||||
|
||||
// Version is the current release version of the OpenTelemetry
|
||||
// Operations Metric Exporter in use.
|
||||
func Version() string {
|
||||
return "0.48.1"
|
||||
}
|
||||
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping/LICENSE
generated
vendored
Normal file
202
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
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.
|
||||
286
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping/resourcemapping.go
generated
vendored
Normal file
286
vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping/resourcemapping.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 resourcemapping
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
|
||||
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
|
||||
)
|
||||
|
||||
const (
|
||||
ProjectIDAttributeKey = "gcp.project.id"
|
||||
|
||||
awsAccount = "aws_account"
|
||||
awsEc2Instance = "aws_ec2_instance"
|
||||
clusterName = "cluster_name"
|
||||
containerName = "container_name"
|
||||
gceInstance = "gce_instance"
|
||||
genericNode = "generic_node"
|
||||
genericTask = "generic_task"
|
||||
instanceID = "instance_id"
|
||||
job = "job"
|
||||
k8sCluster = "k8s_cluster"
|
||||
k8sContainer = "k8s_container"
|
||||
k8sNode = "k8s_node"
|
||||
k8sPod = "k8s_pod"
|
||||
location = "location"
|
||||
namespace = "namespace"
|
||||
namespaceName = "namespace_name"
|
||||
nodeID = "node_id"
|
||||
nodeName = "node_name"
|
||||
podName = "pod_name"
|
||||
region = "region"
|
||||
taskID = "task_id"
|
||||
zone = "zone"
|
||||
gaeInstance = "gae_instance"
|
||||
gaeApp = "gae_app"
|
||||
gaeModuleID = "module_id"
|
||||
gaeVersionID = "version_id"
|
||||
cloudRunRevision = "cloud_run_revision"
|
||||
cloudFunction = "cloud_function"
|
||||
cloudFunctionName = "function_name"
|
||||
serviceName = "service_name"
|
||||
configurationName = "configuration_name"
|
||||
revisionName = "revision_name"
|
||||
bmsInstance = "baremetalsolution.googleapis.com/Instance"
|
||||
unknownServicePrefix = "unknown_service"
|
||||
)
|
||||
|
||||
var (
|
||||
// monitoredResourceMappings contains mappings of GCM resource label keys onto mapping config from OTel
|
||||
// resource for a given monitored resource type.
|
||||
monitoredResourceMappings = map[string]map[string]struct {
|
||||
// If none of the otelKeys are present in the Resource, fallback to this literal value
|
||||
fallbackLiteral string
|
||||
// OTel resource keys to try and populate the resource label from. For entries with
|
||||
// multiple OTel resource keys, the keys' values will be coalesced in order until there
|
||||
// is a non-empty value.
|
||||
otelKeys []string
|
||||
}{
|
||||
gceInstance: {
|
||||
zone: {otelKeys: []string{string(semconv.CloudAvailabilityZoneKey)}},
|
||||
instanceID: {otelKeys: []string{string(semconv.HostIDKey)}},
|
||||
},
|
||||
k8sContainer: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
clusterName: {otelKeys: []string{string(semconv.K8SClusterNameKey)}},
|
||||
namespaceName: {otelKeys: []string{string(semconv.K8SNamespaceNameKey)}},
|
||||
podName: {otelKeys: []string{string(semconv.K8SPodNameKey)}},
|
||||
containerName: {otelKeys: []string{string(semconv.K8SContainerNameKey)}},
|
||||
},
|
||||
k8sPod: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
clusterName: {otelKeys: []string{string(semconv.K8SClusterNameKey)}},
|
||||
namespaceName: {otelKeys: []string{string(semconv.K8SNamespaceNameKey)}},
|
||||
podName: {otelKeys: []string{string(semconv.K8SPodNameKey)}},
|
||||
},
|
||||
k8sNode: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
clusterName: {otelKeys: []string{string(semconv.K8SClusterNameKey)}},
|
||||
nodeName: {otelKeys: []string{string(semconv.K8SNodeNameKey)}},
|
||||
},
|
||||
k8sCluster: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
clusterName: {otelKeys: []string{string(semconv.K8SClusterNameKey)}},
|
||||
},
|
||||
gaeInstance: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
gaeModuleID: {otelKeys: []string{string(semconv.FaaSNameKey)}},
|
||||
gaeVersionID: {otelKeys: []string{string(semconv.FaaSVersionKey)}},
|
||||
instanceID: {otelKeys: []string{string(semconv.FaaSInstanceKey)}},
|
||||
},
|
||||
gaeApp: {
|
||||
location: {otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
}},
|
||||
gaeModuleID: {otelKeys: []string{string(semconv.FaaSNameKey)}},
|
||||
gaeVersionID: {otelKeys: []string{string(semconv.FaaSVersionKey)}},
|
||||
},
|
||||
awsEc2Instance: {
|
||||
instanceID: {otelKeys: []string{string(semconv.HostIDKey)}},
|
||||
region: {
|
||||
otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
},
|
||||
},
|
||||
awsAccount: {otelKeys: []string{string(semconv.CloudAccountIDKey)}},
|
||||
},
|
||||
bmsInstance: {
|
||||
location: {otelKeys: []string{string(semconv.CloudRegionKey)}},
|
||||
instanceID: {otelKeys: []string{string(semconv.HostIDKey)}},
|
||||
},
|
||||
genericTask: {
|
||||
location: {
|
||||
otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
},
|
||||
fallbackLiteral: "global",
|
||||
},
|
||||
namespace: {otelKeys: []string{string(semconv.ServiceNamespaceKey)}},
|
||||
job: {otelKeys: []string{string(semconv.ServiceNameKey), string(semconv.FaaSNameKey)}},
|
||||
taskID: {otelKeys: []string{string(semconv.ServiceInstanceIDKey), string(semconv.FaaSInstanceKey)}},
|
||||
},
|
||||
genericNode: {
|
||||
location: {
|
||||
otelKeys: []string{
|
||||
string(semconv.CloudAvailabilityZoneKey),
|
||||
string(semconv.CloudRegionKey),
|
||||
},
|
||||
fallbackLiteral: "global",
|
||||
},
|
||||
namespace: {otelKeys: []string{string(semconv.ServiceNamespaceKey)}},
|
||||
nodeID: {otelKeys: []string{string(semconv.HostIDKey), string(semconv.HostNameKey)}},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// ReadOnlyAttributes is an interface to abstract between pulling attributes from PData library or OTEL SDK.
|
||||
type ReadOnlyAttributes interface {
|
||||
GetString(string) (string, bool)
|
||||
}
|
||||
|
||||
// ResourceAttributesToLoggingMonitoredResource converts from a set of OTEL resource attributes into a
|
||||
// GCP monitored resource type and label set for Cloud Logging.
|
||||
// E.g.
|
||||
// This may output `gce_instance` type with appropriate labels.
|
||||
func ResourceAttributesToLoggingMonitoredResource(attrs ReadOnlyAttributes) *monitoredrespb.MonitoredResource {
|
||||
cloudPlatform, _ := attrs.GetString(string(semconv.CloudPlatformKey))
|
||||
switch cloudPlatform {
|
||||
case semconv.CloudPlatformGCPAppEngine.Value.AsString():
|
||||
return createMonitoredResource(gaeApp, attrs)
|
||||
default:
|
||||
return commonResourceAttributesToMonitoredResource(cloudPlatform, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceAttributesToMonitoringMonitoredResource converts from a set of OTEL resource attributes into a
|
||||
// GCP monitored resource type and label set for Cloud Monitoring
|
||||
// E.g.
|
||||
// This may output `gce_instance` type with appropriate labels.
|
||||
func ResourceAttributesToMonitoringMonitoredResource(attrs ReadOnlyAttributes) *monitoredrespb.MonitoredResource {
|
||||
cloudPlatform, _ := attrs.GetString(string(semconv.CloudPlatformKey))
|
||||
switch cloudPlatform {
|
||||
case semconv.CloudPlatformGCPAppEngine.Value.AsString():
|
||||
return createMonitoredResource(gaeInstance, attrs)
|
||||
default:
|
||||
return commonResourceAttributesToMonitoredResource(cloudPlatform, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func commonResourceAttributesToMonitoredResource(cloudPlatform string, attrs ReadOnlyAttributes) *monitoredrespb.MonitoredResource {
|
||||
switch cloudPlatform {
|
||||
case semconv.CloudPlatformGCPComputeEngine.Value.AsString():
|
||||
return createMonitoredResource(gceInstance, attrs)
|
||||
case semconv.CloudPlatformAWSEC2.Value.AsString():
|
||||
return createMonitoredResource(awsEc2Instance, attrs)
|
||||
// TODO(alex-basinov): replace this string literal with semconv.CloudPlatformGCPBareMetalSolution
|
||||
// once https://github.com/open-telemetry/semantic-conventions/pull/64 makes its way
|
||||
// into the semconv module.
|
||||
case "gcp_bare_metal_solution":
|
||||
return createMonitoredResource(bmsInstance, attrs)
|
||||
default:
|
||||
// if k8s.cluster.name is set, pattern match for various k8s resources.
|
||||
// this will also match non-cloud k8s platforms like minikube.
|
||||
if _, ok := attrs.GetString(string(semconv.K8SClusterNameKey)); ok {
|
||||
// Try for most to least specific k8s_container, k8s_pod, etc
|
||||
if _, ok := attrs.GetString(string(semconv.K8SContainerNameKey)); ok {
|
||||
return createMonitoredResource(k8sContainer, attrs)
|
||||
} else if _, ok := attrs.GetString(string(semconv.K8SPodNameKey)); ok {
|
||||
return createMonitoredResource(k8sPod, attrs)
|
||||
} else if _, ok := attrs.GetString(string(semconv.K8SNodeNameKey)); ok {
|
||||
return createMonitoredResource(k8sNode, attrs)
|
||||
} else {
|
||||
return createMonitoredResource(k8sCluster, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to generic_task
|
||||
_, hasServiceName := attrs.GetString(string(semconv.ServiceNameKey))
|
||||
_, hasFaaSName := attrs.GetString(string(semconv.FaaSNameKey))
|
||||
_, hasServiceInstanceID := attrs.GetString(string(semconv.ServiceInstanceIDKey))
|
||||
_, hasFaaSInstance := attrs.GetString(string(semconv.FaaSInstanceKey))
|
||||
if (hasServiceName && hasServiceInstanceID) || (hasFaaSInstance && hasFaaSName) {
|
||||
return createMonitoredResource(genericTask, attrs)
|
||||
}
|
||||
|
||||
// Everything else fallback to generic_node
|
||||
return createMonitoredResource(genericNode, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func createMonitoredResource(
|
||||
monitoredResourceType string,
|
||||
resourceAttrs ReadOnlyAttributes,
|
||||
) *monitoredrespb.MonitoredResource {
|
||||
mappings := monitoredResourceMappings[monitoredResourceType]
|
||||
mrLabels := make(map[string]string, len(mappings))
|
||||
|
||||
for mrKey, mappingConfig := range mappings {
|
||||
mrValue := ""
|
||||
ok := false
|
||||
// Coalesce the possible keys in order
|
||||
for _, otelKey := range mappingConfig.otelKeys {
|
||||
mrValue, ok = resourceAttrs.GetString(otelKey)
|
||||
if mrValue != "" && !strings.HasPrefix(mrValue, unknownServicePrefix) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if mrValue == "" && contains(mappingConfig.otelKeys, string(semconv.ServiceNameKey)) {
|
||||
// the service name started with unknown_service, and was ignored above
|
||||
mrValue, ok = resourceAttrs.GetString(string(semconv.ServiceNameKey))
|
||||
}
|
||||
if !ok || mrValue == "" {
|
||||
mrValue = mappingConfig.fallbackLiteral
|
||||
}
|
||||
mrLabels[mrKey] = sanitizeUTF8(mrValue)
|
||||
}
|
||||
return &monitoredrespb.MonitoredResource{
|
||||
Type: monitoredResourceType,
|
||||
Labels: mrLabels,
|
||||
}
|
||||
}
|
||||
|
||||
func contains(list []string, element string) bool {
|
||||
for _, item := range list {
|
||||
if item == element {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func sanitizeUTF8(s string) string {
|
||||
return strings.ToValidUTF8(s, "<22>")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue