1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ import { CloudMonitoringExporter } from './exporter' ;
1516import {
1617 IMetricsHandler ,
1718 OnAttemptCompleteData ,
@@ -20,13 +21,39 @@ import {
2021import * as Resources from '@opentelemetry/resources' ;
2122import * as ResourceUtil from '@google-cloud/opentelemetry-resource-util' ;
2223import { PushMetricExporter , View } from '@opentelemetry/sdk-metrics' ;
24+ import { ClientOptions } from 'google-gax' ;
2325const {
2426 Aggregation,
2527 ExplicitBucketHistogramAggregation,
2628 MeterProvider,
2729 Histogram,
2830 PeriodicExportingMetricReader,
2931} = require ( '@opentelemetry/sdk-metrics' ) ;
32+ import * as os from 'os' ;
33+ import * as crypto from 'crypto' ;
34+
35+ /**
36+ * Generates a unique client identifier string.
37+ *
38+ * This function creates a client identifier that incorporates the hostname,
39+ * process ID, and a UUID to ensure uniqueness across different client instances
40+ * and processes. The identifier follows the pattern:
41+ *
42+ * `node-<uuid>-<pid><hostname>`
43+ *
44+ * where:
45+ * - `<uuid>` is a randomly generated UUID (version 4).
46+ * - `<pid>` is the process ID of the current Node.js process.
47+ * - `<hostname>` is the hostname of the machine.
48+ *
49+ * @returns {string } A unique client identifier string.
50+ */
51+ function generateClientUuid ( ) {
52+ const hostname = os . hostname ( ) || 'localhost' ;
53+ const currentPid = process . pid || '' ;
54+ const uuid4 = crypto . randomUUID ( ) ;
55+ return `node-${ uuid4 } -${ currentPid } ${ hostname } ` ;
56+ }
3057
3158/**
3259 * A collection of OpenTelemetry metric instruments used to record
@@ -47,10 +74,9 @@ interface MetricsInstruments {
4774 * This method gets the open telemetry instruments that will store GCP metrics
4875 * for a particular project.
4976 *
50- * @param projectId The project for which the instruments will be stored.
5177 * @param exporter The exporter the metrics will be sent to.
5278 */
53- function createInstruments ( projectId : string , exporter : PushMetricExporter ) {
79+ function createInstruments ( exporter : PushMetricExporter ) : MetricsInstruments {
5480 const latencyBuckets = [
5581 0.0 , 1.0 , 2.0 , 3.0 , 4.0 , 5.0 , 6.0 , 8.0 , 10.0 , 13.0 , 16.0 , 20.0 , 25.0 , 30.0 ,
5682 40.0 , 50.0 , 65.0 , 80.0 , 100.0 , 130.0 , 160.0 , 200.0 , 250.0 , 300.0 , 400.0 ,
@@ -80,7 +106,6 @@ function createInstruments(projectId: string, exporter: PushMetricExporter) {
80106 views : viewList ,
81107 resource : new Resources . Resource ( {
82108 'service.name' : 'Cloud Bigtable Table' ,
83- 'monitored_resource.project_id' : projectId ,
84109 } ) . merge ( new ResourceUtil . GcpDetectorSync ( ) . detect ( ) ) ,
85110 readers : [
86111 // Register the exporter
@@ -183,11 +208,8 @@ function createInstruments(projectId: string, exporter: PushMetricExporter) {
183208 * associating them with relevant attributes for detailed analysis in Cloud Monitoring.
184209 */
185210export class GCPMetricsHandler implements IMetricsHandler {
186- private exporter : PushMetricExporter ;
187- // The variable below is the singleton map from projects to instrument stacks
188- // which exists so that we only create one instrument stack per project. This
189- // will eliminate errors due to the maximum sampling period.
190- static instrumentsForProject : { [ projectId : string ] : MetricsInstruments } = { } ;
211+ private otelInstruments : MetricsInstruments ;
212+ private clientUid : string ;
191213
192214 /**
193215 * The `GCPMetricsHandler` is responsible for managing and recording
@@ -196,33 +218,11 @@ export class GCPMetricsHandler implements IMetricsHandler {
196218 * (histograms and counters) and exports them to Google Cloud Monitoring
197219 * through the provided `PushMetricExporter`.
198220 *
199- * @param exporter - The `PushMetricExporter` instance to use for exporting
200- * metrics to Google Cloud Monitoring. This exporter is responsible for
201- * sending the collected metrics data to the monitoring backend. The provided exporter must be fully configured, for example the projectId must have been set.
202221 */
203- constructor ( exporter : PushMetricExporter ) {
204- this . exporter = exporter ;
205- }
206-
207- /**
208- * Initializes the OpenTelemetry metrics instruments if they haven't been already.
209- * Creates and registers metric instruments (histograms and counters) for various Bigtable client metrics.
210- * Sets up a MeterProvider and configures a PeriodicExportingMetricReader for exporting metrics to Cloud Monitoring.
211- *
212- * which will be provided to the exporter in every export call.
213- *
214- */
215- private getInstruments ( projectId : string ) : MetricsInstruments {
216- // The projectId is needed per metrics handler because when the exporter is
217- // used it provides the project id for the name of the time series exported.
218- // ie. name: `projects/${....['monitored_resource.project_id']}`,
219- if ( ! GCPMetricsHandler . instrumentsForProject [ projectId ] ) {
220- GCPMetricsHandler . instrumentsForProject [ projectId ] = createInstruments (
221- projectId ,
222- this . exporter ,
223- ) ;
224- }
225- return GCPMetricsHandler . instrumentsForProject [ projectId ] ;
222+ constructor ( options : ClientOptions ) {
223+ this . clientUid = generateClientUuid ( ) ;
224+ const exporter = new CloudMonitoringExporter ( options ) ;
225+ this . otelInstruments = createInstruments ( exporter ) ;
226226 }
227227
228228 /**
@@ -231,11 +231,11 @@ export class GCPMetricsHandler implements IMetricsHandler {
231231 * @param {OnOperationCompleteData } data Data related to the completed operation.
232232 */
233233 onOperationComplete ( data : OnOperationCompleteData ) {
234- const otelInstruments = this . getInstruments ( data . projectId ) ;
234+ const otelInstruments = this . otelInstruments ;
235235 const commonAttributes = {
236236 app_profile : data . metricsCollectorData . app_profile ,
237237 method : data . metricsCollectorData . method ,
238- client_uid : data . metricsCollectorData . client_uid ,
238+ client_uid : this . clientUid ,
239239 client_name : data . client_name ,
240240 instanceId : data . metricsCollectorData . instanceId ,
241241 table : data . metricsCollectorData . table ,
@@ -271,11 +271,11 @@ export class GCPMetricsHandler implements IMetricsHandler {
271271 * @param {OnAttemptCompleteData } data Data related to the completed attempt.
272272 */
273273 onAttemptComplete ( data : OnAttemptCompleteData ) {
274- const otelInstruments = this . getInstruments ( data . projectId ) ;
274+ const otelInstruments = this . otelInstruments ;
275275 const commonAttributes = {
276276 app_profile : data . metricsCollectorData . app_profile ,
277277 method : data . metricsCollectorData . method ,
278- client_uid : data . metricsCollectorData . client_uid ,
278+ client_uid : this . clientUid ,
279279 status : data . status ,
280280 client_name : data . client_name ,
281281 instanceId : data . metricsCollectorData . instanceId ,
0 commit comments