Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diagnose tool #251

Merged
merged 2 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 51 additions & 14 deletions packages/nodejs-ext/scripts/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ const {
hasSupportedOs
} = require("./extension/helpers")

const { createReport } = require("./report")
const {
createReport,
createBuildReport,
createDownloadReport
} = require("./report")

const EXT_PATH = path.join(__dirname, "/../ext/")

Expand Down Expand Up @@ -60,9 +64,23 @@ function verify(filepath, checksum) {
})
}

function getMetadataForTarget(report) {
const { architecture, target, muslOverride } = report.build
function dumpReport(report) {
return new Promise(resolve => {
fs.writeFile(
"/tmp/appsignal-install-report.json",
JSON.stringify(report, null, 2),
() => {
return resolve()
}
)
})
}

function getMetadataForTarget({
architecture,
target,
musl_override: muslOverride
}) {
const triple = [
architecture === "x64" ? "x86_64" : "i686",
`-${target}`,
Expand All @@ -74,15 +92,13 @@ function getMetadataForTarget(report) {

// Script logic begins here
;(function () {
const report = createReport()

if (hasLocalBuild()) {
// check for a local build (dev only)
console.warn(`Using local build for agent. Skipping download.`)
return process.exit(0)
}

if (!hasSupportedArchitecture(report)) {
if (!hasSupportedArchitecture(process.arch)) {
console.error(
`AppSignal currently does not support your system architecture
(${process.platform} ${process.arch}). Please let us know at
Expand All @@ -92,7 +108,7 @@ function getMetadataForTarget(report) {
return process.exit(1)
}

if (!hasSupportedOs(report)) {
if (!hasSupportedOs(process.platform)) {
console.error(
`AppSignal currently does not support your operating system (${process.platform}).
Please let us know at support@appsignal.com, we aim to support everything
Expand All @@ -102,23 +118,44 @@ function getMetadataForTarget(report) {
return process.exit(1)
}

const report = createReport()
report.build = createBuildReport({})

// try and get one from the CDN
const metadata = getMetadataForTarget(report)
const metadata = getMetadataForTarget(report.build)
const filename = metadata.downloadUrl.split("/")[4]
const outputPath = path.join(EXT_PATH, filename)

return download(metadata.downloadUrl, outputPath)
.then(filepath => {
return verify(filepath, metadata.checksum).then(() => extract(filepath))
})
.then(filepath =>
verify(filepath, metadata.checksum).then(() => extract(filepath))
)
.then(() => {
// once extracted, we can then hand off to node-gyp for building
// @TODO: add cleanup step
console.log("The agent has installed successfully!")
process.exit(0)
console.log("The agent has downloaded successfully! Building...")

report.download = createDownloadReport({
verified: true,
downloadUrl: metadata.downloadUrl
})

report.result.status = "success"

return dumpReport(report).then(() => {
process.exit(0)
})
})
.catch(error => {
console.error(error)
process.exit(1)

report.download = createDownloadReport({
verified: false,
downloadUrl: metadata.downloadUrl
})

return dumpReport(report).then(() => {
process.exit(1)
})
})
})()
14 changes: 4 additions & 10 deletions packages/nodejs-ext/scripts/extension/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ function hasLocalBuild() {
*
* @return {boolean}
*/
function hasSupportedArchitecture(report) {
function hasSupportedArchitecture(arch) {
// 'x32' and 'x64' supported
return (
report.build.architecture === "x32" || report.build.architecture === "x64"
)
return arch === "x32" || arch === "x64"
}

/**
Expand All @@ -36,12 +34,8 @@ function hasSupportedArchitecture(report) {
*
* @return {boolean}
*/
function hasSupportedOs(report) {
return (
report.build.target === "darwin" ||
report.build.target === "freebsd" ||
report.build.target === "linux"
)
function hasSupportedOs(os) {
return os === "darwin" || os === "freebsd" || os === "linux"
}

/**
Expand Down
48 changes: 37 additions & 11 deletions packages/nodejs-ext/scripts/report.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
const path = require("path")

const { AGENT_VERSION } = require("./extension/constants")
const { hasMusl } = require("./extension/helpers")

function createReport() {
return {
result: { status: "incomplete" },
language: {
name: "nodejs",
version: process.versions["node"]
},
build: {
time: new Date().toISOString(),
packagePath: path.join(__dirname, "/../ext/"),
architecture: process.arch,
target: process.platform,
muslOverride: (process.env["APPSIGNAL_BUILD_FOR_MUSL"] === "true") || hasMusl(),
libraryType: "static"
version: process.versions["node"],
implementation: "nodejs"
},
download: {},
build: {},
host: {
rootUser: process.getuid && process.getuid() === 0,
root_user: process.getuid && process.getuid() === 0,
dependencies: {}
}
}
}

exports.createReport = createReport
function createBuildReport({ isLocalBuild = false }) {
return {
time: new Date().toISOString(),
package_path: path.join(__dirname, "/../ext/"),
architecture: process.arch,
target: process.platform,
musl_override:
process.env["APPSIGNAL_BUILD_FOR_MUSL"] === "true" || hasMusl(),
library_type: "static",
dependencies: {},
flags: {},
source: isLocalBuild ? "local" : "remote",
agent_version: AGENT_VERSION
}
}

function createDownloadReport({ verified = false, downloadUrl: download_url }) {
return {
checksum: verified ? "verified" : "unverified",
http_proxy: null,
download_url
}
}

module.exports = {
createReport,
createBuildReport,
createDownloadReport
}
52 changes: 52 additions & 0 deletions packages/nodejs/bin/diagnose
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env node

const https = require("https")
const { DiagnoseTool } = require("../dist/diagnose")

// enable diagnose mode
process.env["_APPSIGNAL_DIAGNOSE"] = "true"

const tool = new DiagnoseTool({})

console.log(`
🔧 AppSignal Diagnose Tool

Use this information to debug your configuration.
More information is available on the documentation site.
https://docs.appsignal.com/

This diagnose output was sent to AppSignal, contact us at support@appsignal.com if you need help.
`)

if (!process.env["APPSIGNAL_PUSH_API_KEY"]) {
throw new Error(`No Push API key found. Set the APPSIGNAL_PUSH_API_KEY environment variable to your Push API key and try again.`)
}

const data = tool.generate()
const json = JSON.stringify(data)

const opts = {
port: 443,
method: "POST",
host: "appsignal.com",
path: "/diag",
headers: {
"Content-Type": "application/json",
"Content-Length": json.length
}
}

const req = https.request(opts, res => {
res.setEncoding("utf8")
})

req.on("error", e => {
console.error(`Problem with diagnose request: ${e.message}`)
})

// Write data to request body
req.write(json)
req.end()

console.log(data, "\n")
console.log("✅ Done!")
3 changes: 3 additions & 0 deletions packages/nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"main": "dist/index",
"types": "dist/index",
"license": "MIT",
"bin": {
"appsignal-diagnose": "./bin/diagnose"
},
"dependencies": {
"@appsignal/core": "^1.0.9",
"@appsignal/types": "^1.0.0",
Expand Down
6 changes: 5 additions & 1 deletion packages/nodejs/scripts/create-versionfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

const fs = require("fs")
const pkg = require("../package.json")
const {
AGENT_VERSION
} = require("../../nodejs-ext/scripts/extension/constants")

const data = `// Do not touch this file, auto-generated by scripts/create-versionfile
export const VERSION = "${pkg.version}"\n`
export const VERSION = "${pkg.version}"
export const AGENT_VERSION = "${AGENT_VERSION}"\n`

fs.writeFile(`${process.cwd()}/src/version.ts`, data, "utf8", err => {
if (err) throw err
Expand Down
4 changes: 4 additions & 0 deletions packages/nodejs/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,8 @@ export class Agent {

return this.isLoaded
}

public diagnose(): string {
return JSON.parse(extension.diagnoseRaw())
}
}
8 changes: 4 additions & 4 deletions packages/nodejs/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import { ENV_TO_KEY_MAPPING, PRIVATE_ENV_MAPPING } from "./config/configmap"
* @class
*/
export class Configuration {
private _data: Partial<AppsignalOptions>
public data: Partial<AppsignalOptions>

constructor(options: Partial<AppsignalOptions>) {
writePrivateConstants()

this._data = {
this.data = {
debug: false,
log: "file",
logPath: "/tmp/appsignal.log",
Expand All @@ -28,14 +28,14 @@ export class Configuration {
...options
}

this._write(this._data)
this._write(this.data)
}

/**
* Returns `true` if the client is in debug mode
*/
public get debug(): boolean {
return this._data.debug || false
return this.data.debug || false
}

/**
Expand Down
27 changes: 25 additions & 2 deletions packages/nodejs/src/config/configmap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const ENV_TO_KEY_MAPPING = {
export const ENV_TO_KEY_MAPPING: { [key: string]: string } = {
APPSIGNAL_ACTIVE: "active",
APPSIGNAL_PUSH_API_KEY: "apiKey",
APPSIGNAL_APP_NAME: "name",
Expand Down Expand Up @@ -28,7 +28,7 @@ export const ENV_TO_KEY_MAPPING = {
APP_REVISION: "revision"
}

export const PRIVATE_ENV_MAPPING = {
export const PRIVATE_ENV_MAPPING: { [key: string]: string } = {
_APPSIGNAL_ACTIVE: "active",
_APPSIGNAL_ENVIRONMENT: "environment",
_APPSIGNAL_DEBUG_LOGGING: "debug",
Expand All @@ -52,3 +52,26 @@ export const PRIVATE_ENV_MAPPING = {
_APPSIGNAL_FILES_WORLD_ACCESSIBLE: "filesWorldAccessible",
_APP_REVISION: "revision"
}

export const JS_TO_RUBY_MAPPING: { [key: string]: string } = {
active: "active",
environment: "env",
debug: "debug",
log: "log",
logPath: "log_path",
endpoint: "endpoint",
apiKey: "push_api_key",
name: "name",
ignoreActions: "ignore_actions",
ignoreErrors: "ignore_errors",
ignoreNamespaces: "ignore_namespaces",
runningInContainer: "running_in_container",
workingDirPath: "working_dir_path",
workingDirectoryPath: "working_directory_path",
enableHostMetrics: "enable_host_metrics",
hostname: "hostname",
caFilePath: "ca_file_path",
dnsServers: "dns_servers",
filesWorldAccessible: "files_world_accessible",
revision: "revision"
}
Loading