pm2
Version:
Production process manager for Node.JS applications with a built-in load balancer.
150 lines (139 loc) • 4.3 kB
JavaScript
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.
*/
const { diag } = require('@opentelemetry/api')
const { ExportResultCode } = require('@opentelemetry/core')
const { prepareSend } = require('./platform/index')
const zipkinTypes = require('./types')
const {
toZipkinSpan,
defaultStatusCodeTagName,
defaultStatusErrorTagName,
} = require('./transform')
const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions')
const { prepareGetHeaders } = require('./utils')
const { ServiceManager } = require('../../serviceManager')
/**
* Zipkin Exporter
*/
class CustomZipkinExporter {
constructor (config = {}) {
this.DEFAULT_SERVICE_NAME = 'OpenTelemetry Service'
this._urlStr = config.url || process.env.OTEL_EXPORTER_ZIPKIN_ENDPOINT || 'http://localhost:9411/api/v2/spans'
this.transport = ServiceManager.get('transport')
this._send = prepareSend(this.transport, config.headers)
this._serviceName = config.serviceName
this._statusCodeTagName =
config.statusCodeTagName || defaultStatusCodeTagName
this._statusDescriptionTagName =
config.statusDescriptionTagName || defaultStatusErrorTagName
this._isShutdown = false
this._sendingPromises = []
if (typeof config.getExportRequestHeaders === 'function') {
this._getHeaders = prepareGetHeaders(config.getExportRequestHeaders)
} else {
// noop
this._beforeSend = function () {}
}
}
/**
* Export spans.
*/
export (spans, resultCallback) {
if (spans.length === 0) {
return resultCallback({ code: ExportResultCode.SUCCESS })
}
const serviceName = String(
this._serviceName ||
spans[0].resource.attributes[ATTR_SERVICE_NAME] ||
this.DEFAULT_SERVICE_NAME
)
diag.debug('Zipkin exporter export')
if (this._isShutdown) {
setTimeout(() =>
resultCallback({
code: ExportResultCode.FAILED,
error: new Error('Exporter has been shutdown'),
}), 0
)
return
}
const promise = new Promise(resolve => {
this._sendSpans(spans, serviceName, result => {
resolve()
resultCallback(result)
})
})
this._sendingPromises.push(promise)
const popPromise = () => {
const index = this._sendingPromises.indexOf(promise)
this._sendingPromises.splice(index, 1)
}
promise.then(popPromise, popPromise)
}
/**
* Shutdown exporter. Noop operation in this exporter.
*/
shutdown () {
diag.debug('Zipkin exporter shutdown')
this._isShutdown = true
return this.forceFlush()
}
/**
* Exports any pending spans in exporter
*/
forceFlush () {
return new Promise((resolve, reject) => {
Promise.all(this._sendingPromises).then(() => {
resolve()
}, reject)
})
}
/**
* if user defines getExportRequestHeaders in config then this will be called
* every time before send, otherwise it will be replaced with noop in
* constructor
* @default noop
*/
_beforeSend () {
if (this._getHeaders) {
this._send = prepareSend(this.transport, this._getHeaders())
}
}
/**
* Transform spans and sends to Zipkin service.
*/
_sendSpans (spans, serviceName, done) {
const zipkinSpans = spans.map(span =>
toZipkinSpan(
span,
String(
span.attributes[ATTR_SERVICE_NAME] ||
span.resource.attributes[ATTR_SERVICE_NAME] ||
serviceName
),
this._statusCodeTagName,
this._statusDescriptionTagName
)
)
this._beforeSend()
return this._send(zipkinSpans, (result) => {
if (done) {
return done(result)
}
})
}
}
module.exports = { CustomZipkinExporter }