newrelic
Version:
New Relic agent
142 lines (120 loc) • 4.85 kB
JavaScript
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
const fetchSystemInfo = require('../system-info')
const defaultLogger = require('../logger').child({ component: 'facts' })
const os = require('os')
module.exports = facts
async function facts(agent, callback, { logger = defaultLogger } = {}) {
const startTime = Date.now()
const systemInfoPromise = new Promise((resolve) => {
fetchSystemInfo(agent, (_, data) => {
resolve(data)
})
})
const environmentPromise = agent.environment.getJSON()
let [systemInfo, environment] = await Promise.all([systemInfoPromise, environmentPromise])
logger.trace('Facts gathering finished in %dms', Date.now() - startTime)
if (environment.failed) {
logger.debug(environment.err, 'Failed to load system facts!')
}
systemInfo = systemInfo || Object.create(null)
environment = environment || []
const hostname = agent.config.getHostnameSafe(systemInfo?.vendors?.gcp?.id)
const results = {
utilization: {
metadata_version: 5,
logical_processors: systemInfo.logicalProcessors || null,
total_ram_mib: systemInfo.memory || null,
hostname
},
pid: process.pid,
host: hostname,
display_host: agent.config.getDisplayHost() || hostname,
language: 'nodejs',
app_name: agent.config.applications(),
agent_version: agent.version,
environment,
settings: agent.config.publicSettings(),
high_security: agent.config.high_security,
labels: agent.config.parsedLabels,
metadata: Object.keys(process.env).reduce((obj, key) => {
if (key.startsWith('NEW_RELIC_METADATA_')) {
obj[key] = process.env[key]
}
return obj
}, {})
}
logger.debug('New Relic metadata %o', results.metadata)
/**
* WARNING: This may not make sense if you are familiar with our config
* and updating of config from server. But the intention here is to always
* send the values from user config of harvest limits because on connect these
* values get reconfigured based on harvest cycle intervals. So if you originally
* had 1000 and a harvest of 5 seconds the new value of the harvest limit would be 83.
* Then every subsequent connect request it would continue to decrease until it eventually hit 0
* and we would never be sampling a certain piece of data.
*/
results.event_harvest_config = {
harvest_limits: {
analytic_event_data: agent.config.transaction_events.max_samples_stored,
custom_event_data: agent.config.custom_insights_events.max_samples_stored,
error_event_data: agent.config.error_collector.max_event_samples_stored,
span_event_data: agent.config.span_events.max_samples_stored,
log_event_data: agent.config.application_logging.forwarding.max_samples_stored
}
}
results.identifier = getIdentifierOverride(results.app_name)
const ipAddresses = getAllIPAddresses()
if (ipAddresses.length) {
results.utilization.ip_address = ipAddresses
}
if (systemInfo.bootId) {
results.utilization.boot_id = systemInfo.bootId
}
if (systemInfo.vendors) {
results.utilization.vendors = systemInfo.vendors
}
if (systemInfo.config) {
results.utilization.config = systemInfo.config
}
callback(results)
}
function getAllIPAddresses() {
const interfaces = os.networkInterfaces()
const localRegex = /^lo/
return Object.keys(interfaces).reduce(function gatherAddresses(addresses, key) {
if (!localRegex.test(key)) {
const interfaceAddresses = interfaces[key].map(function getAddress(inter) {
return inter.address
})
for (let index = 0; index < interfaceAddresses.length; index++) {
const address = interfaceAddresses[index]
addresses.push(address)
}
}
return addresses
}, [])
}
/**
* Creates an identifier override to support customers who have multiple agents on the
* same host with the first app name that is identical.
* https://github.com/newrelic/node-newrelic/commit/c0901e6807a50ac3969d79ab48c31c8e0232a6b5#r18254962
* https://source.datanerd.us/collector-collective/connect-service/blob/1470c21109393a5b43c8788da88a37f41a300b98/src/main/java/com/nr/collector/methods/Connect.java#L1424-L1431
*
* IMPORTANT: we do not include host as it has negative consequences and is unnecessary.
* On the server, the host will still be used as part of the key to determine if two agent
* connections are the same real agent or a separate one.
* https://github.com/newrelic/node-newrelic/issues/654
*
* @param {Array<string>} appNames list of app names
*/
function getIdentifierOverride(appNames) {
return [
'nodejs',
// NOTE: The concat is necessary to prevent sort from happening in-place.
appNames.concat([]).sort().join(',')
].join(':')
}