Standardise all supervisor output logging

Also use the supervisor's own container logging monitoring code when
running livepush on the supervisor container.

Change-type: minor
Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
Cameron Diver 2019-05-30 23:30:49 +01:00
parent 2c1164cd62
commit 2276dd54e1
30 changed files with 917 additions and 402 deletions

588
package-lock.json generated
View File

@ -77,6 +77,25 @@
"strip-ansi": "^3.0.1" "strip-ansi": "^3.0.1"
}, },
"dependencies": { "dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"log-symbols": { "log-symbols": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz",
@ -85,6 +104,21 @@
"requires": { "requires": {
"chalk": "^1.0.0" "chalk": "^1.0.0"
} }
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
} }
} }
}, },
@ -326,7 +360,7 @@
}, },
"@types/optimist": { "@types/optimist": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/optimist/-/optimist-0.0.29.tgz", "resolved": "http://registry.npmjs.org/@types/optimist/-/optimist-0.0.29.tgz",
"integrity": "sha1-qIc1gLOoS2msHmhzI7Ffu+uQR5o=", "integrity": "sha1-qIc1gLOoS2msHmhzI7Ffu+uQR5o=",
"dev": true "dev": true
}, },
@ -686,12 +720,6 @@
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}, },
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"any-observable": { "any-observable": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz",
@ -773,12 +801,6 @@
"integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
"dev": true "dev": true
}, },
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
"dev": true
},
"array-map": { "array-map": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
@ -928,6 +950,44 @@
"chalk": "^1.1.3", "chalk": "^1.1.3",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"js-tokens": "^3.0.2" "js-tokens": "^3.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
}
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
} }
}, },
"babel-messages": { "babel-messages": {
@ -1230,6 +1290,36 @@
"underscore.string": "^3.2.3" "underscore.string": "^3.2.3"
}, },
"dependencies": { "dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
}
}
},
"docker-toolbelt": { "docker-toolbelt": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/docker-toolbelt/-/docker-toolbelt-1.4.0.tgz", "resolved": "https://registry.npmjs.org/docker-toolbelt/-/docker-toolbelt-1.4.0.tgz",
@ -1243,6 +1333,12 @@
"semver": "^5.2.0", "semver": "^5.2.0",
"tar-stream": "^1.5.2" "tar-stream": "^1.5.2"
} }
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
} }
} }
}, },
@ -1424,19 +1520,6 @@
} }
} }
}, },
"bonjour": {
"version": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
"from": "git+https://github.com/resin-io/bonjour.git#fixed-mdns",
"dev": true,
"requires": {
"array-flatten": "^2.1.0",
"deep-equal": "^1.0.1",
"dns-equal": "^1.0.0",
"dns-txt": "^2.0.2",
"multicast-dns": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
"multicast-dns-service-types": "^1.1.0"
}
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -1603,12 +1686,6 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true "dev": true
}, },
"buffer-indexof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
"integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
"dev": true
},
"buffer-xor": { "buffer-xor": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
@ -1765,19 +1842,6 @@
"integrity": "sha1-xVEoN4+bs5nplPAAUhUZhO1uvnA=", "integrity": "sha1-xVEoN4+bs5nplPAAUhUZhO1uvnA=",
"dev": true "dev": true
}, },
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"check-error": { "check-error": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
@ -1938,6 +2002,17 @@
"string-width": "^1.0.1", "string-width": "^1.0.1",
"strip-ansi": "^3.0.1", "strip-ansi": "^3.0.1",
"wrap-ansi": "^2.0.0" "wrap-ansi": "^2.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
}
} }
}, },
"clone": { "clone": {
@ -1976,7 +2051,7 @@
"dependencies": { "dependencies": {
"coffee-script": { "coffee-script": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.11.1.tgz", "resolved": "http://registry.npmjs.org/coffee-script/-/coffee-script-1.11.1.tgz",
"integrity": "sha1-vxxHrWREOg2V0S3ysUfMCk2q1uk=", "integrity": "sha1-vxxHrWREOg2V0S3ysUfMCk2q1uk=",
"dev": true "dev": true
}, },
@ -2019,6 +2094,16 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"dev": true,
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": { "color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -2034,6 +2119,38 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true "dev": true
}, },
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"dev": true,
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=",
"dev": true
},
"colors": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz",
"integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==",
"dev": true
},
"colorspace": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz",
"integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==",
"dev": true,
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
}
},
"columnify": { "columnify": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz",
@ -2042,6 +2159,17 @@
"requires": { "requires": {
"strip-ansi": "^3.0.0", "strip-ansi": "^3.0.0",
"wcwidth": "^1.0.0" "wcwidth": "^1.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
}
} }
}, },
"combined-stream": { "combined-stream": {
@ -2375,12 +2503,6 @@
} }
} }
}, },
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
"dev": true
},
"deep-extend": { "deep-extend": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@ -2559,6 +2681,17 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
}, },
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"dev": true,
"requires": {
"colorspace": "1.1.x",
"enabled": "1.0.x",
"kuler": "1.0.x"
}
},
"diff": { "diff": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
@ -2586,31 +2719,6 @@
"path-type": "^3.0.0" "path-type": "^3.0.0"
} }
}, },
"dns-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
"dev": true
},
"dns-packet": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
"dev": true,
"requires": {
"ip": "^1.1.0",
"safe-buffer": "^5.0.1"
}
},
"dns-txt": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
"integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
"dev": true,
"requires": {
"buffer-indexof": "^1.0.0"
}
},
"docker-delta": { "docker-delta": {
"version": "2.2.9", "version": "2.2.9",
"resolved": "https://registry.npmjs.org/docker-delta/-/docker-delta-2.2.9.tgz", "resolved": "https://registry.npmjs.org/docker-delta/-/docker-delta-2.2.9.tgz",
@ -3005,6 +3113,15 @@
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true "dev": true
}, },
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"dev": true,
"requires": {
"env-variable": "0.0.x"
}
},
"encodeurl": { "encodeurl": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@ -3039,6 +3156,12 @@
"tapable": "^1.0.0" "tapable": "^1.0.0"
} }
}, },
"env-variable": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==",
"dev": true
},
"errno": { "errno": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@ -3485,6 +3608,18 @@
"integrity": "sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg=", "integrity": "sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg=",
"dev": true "dev": true
}, },
"fast-safe-stringify": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz",
"integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==",
"dev": true
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==",
"dev": true
},
"fetch-ponyfill": { "fetch-ponyfill": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz",
@ -4446,6 +4581,16 @@
"string-width": "^1.0.1", "string-width": "^1.0.1",
"strip-ansi": "^3.0.1", "strip-ansi": "^3.0.1",
"wide-align": "^1.1.0" "wide-align": "^1.1.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
}
} }
}, },
"get-caller-file": { "get-caller-file": {
@ -5088,6 +5233,25 @@
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
"dev": true "dev": true
}, },
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"cli-cursor": { "cli-cursor": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
@ -5129,6 +5293,21 @@
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0" "strip-ansi": "^3.0.0"
} }
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
} }
} }
}, },
@ -5761,6 +5940,15 @@
} }
} }
}, },
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
"dev": true,
"requires": {
"colornames": "^1.1.1"
}
},
"lcid": { "lcid": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
@ -6233,6 +6421,25 @@
"strip-ansi": "^3.0.1" "strip-ansi": "^3.0.1"
}, },
"dependencies": { "dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"log-symbols": { "log-symbols": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz",
@ -6241,6 +6448,21 @@
"requires": { "requires": {
"chalk": "^1.0.0" "chalk": "^1.0.0"
} }
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
} }
} }
}, },
@ -6303,9 +6525,9 @@
} }
}, },
"livepush": { "livepush": {
"version": "1.2.4", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/livepush/-/livepush-1.2.4.tgz", "resolved": "https://registry.npmjs.org/livepush/-/livepush-1.2.5.tgz",
"integrity": "sha512-AKGlJ+QuelyDoOV0cbGfeskLf2RaYIcHnKogfircvTl9//BNDrGVhrcO6bN3kcVaJnYKnvXwXOtGOyrsl6wI9A==", "integrity": "sha512-aPeBngn6Fr4dusLcbEcA4hM90zl4jJCqMNrYIeXqUPTNZwyA7D2SmQJp9EEYJ/9/Q8cOxi78CTY7CYdvdOR0ng==",
"dev": true, "dev": true,
"requires": { "requires": {
"bluebird": "^3.5.1", "bluebird": "^3.5.1",
@ -6333,7 +6555,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -6354,7 +6576,7 @@
}, },
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true "dev": true
} }
@ -6523,6 +6745,27 @@
} }
} }
}, },
"logform": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz",
"integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==",
"dev": true,
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^2.3.3",
"ms": "^2.1.1",
"triple-beam": "^1.3.0"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
}
}
},
"lolex": { "lolex": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz",
@ -7027,21 +7270,6 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true "dev": true
}, },
"multicast-dns": {
"version": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
"from": "git+https://github.com/resin-io-modules/multicast-dns.git#listen-on-all-interfaces",
"dev": true,
"requires": {
"dns-packet": "^1.0.1",
"thunky": "^0.1.0"
}
},
"multicast-dns-service-types": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
"dev": true
},
"mute-stream": { "mute-stream": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
@ -7464,6 +7692,12 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=",
"dev": true
},
"onetime": { "onetime": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
@ -7555,7 +7789,7 @@
}, },
"get-stream": { "get-stream": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
"dev": true "dev": true
} }
@ -8220,7 +8454,7 @@
}, },
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true "dev": true
}, },
@ -8461,9 +8695,22 @@
"dev": true, "dev": true,
"requires": { "requires": {
"bluebird": "^3.0.0", "bluebird": "^3.0.0",
"bonjour": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
"ip": "^1.1.4", "ip": "^1.1.4",
"lodash": "^4.17.4" "lodash": "^4.17.4"
},
"dependencies": {
"bonjour": {
"version": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
"from": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
"requires": {
"array-flatten": "^2.1.0",
"deep-equal": "^1.0.1",
"dns-equal": "^1.0.0",
"dns-txt": "^2.0.2",
"multicast-dns": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
"multicast-dns-service-types": "^1.1.0"
}
}
} }
}, },
"resin-lint": { "resin-lint": {
@ -8938,6 +9185,23 @@
} }
} }
}, },
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"dev": true,
"requires": {
"is-arrayish": "^0.3.1"
},
"dependencies": {
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
}
}
},
"sinon": { "sinon": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-2.4.1.tgz", "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.4.1.tgz",
@ -9312,6 +9576,12 @@
"safe-buffer": "^5.1.1" "safe-buffer": "^5.1.1"
} }
}, },
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
"dev": true
},
"staged-git-files": { "staged-git-files": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz",
@ -9429,6 +9699,16 @@
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0" "strip-ansi": "^3.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
}
} }
}, },
"string_decoder": { "string_decoder": {
@ -9450,14 +9730,6 @@
"is-regexp": "^1.0.0" "is-regexp": "^1.0.0"
} }
}, },
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-bom": { "strip-bom": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@ -9475,12 +9747,6 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
}, },
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
},
"symbol-observable": { "symbol-observable": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
@ -9722,6 +9988,12 @@
"integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
"dev": true "dev": true
}, },
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
"dev": true
},
"thenify": { "thenify": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
@ -9755,12 +10027,6 @@
"xtend": "~4.0.1" "xtend": "~4.0.1"
} }
}, },
"thunky": {
"version": "0.1.0",
"resolved": "http://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
"integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=",
"dev": true
},
"tildify": { "tildify": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz",
@ -9883,6 +10149,12 @@
"ski": "~1.0.0" "ski": "~1.0.0"
} }
}, },
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
"dev": true
},
"ts-loader": { "ts-loader": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.1.tgz", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.1.tgz",
@ -9928,16 +10200,24 @@
} }
}, },
"ts-node": { "ts-node": {
"version": "8.1.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.2.0.tgz",
"integrity": "sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A==", "integrity": "sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==",
"dev": true, "dev": true,
"requires": { "requires": {
"arg": "^4.1.0", "arg": "^4.1.0",
"diff": "^3.1.0", "diff": "^4.0.1",
"make-error": "^1.1.1", "make-error": "^1.1.1",
"source-map-support": "^0.5.6", "source-map-support": "^0.5.6",
"yn": "^3.0.0" "yn": "^3.0.0"
},
"dependencies": {
"diff": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
"dev": true
}
} }
}, },
"tslib": { "tslib": {
@ -11382,6 +11662,55 @@
"string-width": "^1.0.2 || 2" "string-width": "^1.0.2 || 2"
} }
}, },
"winston": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz",
"integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==",
"dev": true,
"requires": {
"async": "^2.6.1",
"diagnostics": "^1.1.1",
"is-stream": "^1.1.0",
"logform": "^2.1.1",
"one-time": "0.0.4",
"readable-stream": "^3.1.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.3.0"
},
"dependencies": {
"async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
"dev": true,
"requires": {
"lodash": "^4.17.11"
}
},
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"winston-transport": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz",
"integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==",
"dev": true,
"requires": {
"readable-stream": "^2.3.6",
"triple-beam": "^1.2.0"
}
},
"wordwrap": { "wordwrap": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
@ -11405,6 +11734,17 @@
"requires": { "requires": {
"string-width": "^1.0.1", "string-width": "^1.0.1",
"strip-ansi": "^3.0.1" "strip-ansi": "^3.0.1"
},
"dependencies": {
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
}
} }
}, },
"wrappy": { "wrappy": {

View File

@ -73,7 +73,7 @@
"json-mask": "^0.3.8", "json-mask": "^0.3.8",
"knex": "~0.15.2", "knex": "~0.15.2",
"lint-staged": "^8.1.0", "lint-staged": "^8.1.0",
"livepush": "^1.2.4", "livepush": "^1.2.5",
"lockfile": "^1.0.1", "lockfile": "^1.0.1",
"lodash": "^4.17.5", "lodash": "^4.17.5",
"log-timestamp": "^0.1.2", "log-timestamp": "^0.1.2",
@ -101,6 +101,7 @@
"typed-error": "^2.0.0", "typed-error": "^2.0.0",
"typescript": "^3.2.2", "typescript": "^3.2.2",
"webpack": "^4.25.0", "webpack": "^4.25.0",
"webpack-cli": "^3.1.2" "webpack-cli": "^3.1.2",
"winston": "^3.2.1"
} }
} }

View File

@ -27,6 +27,8 @@ import { DeviceApplicationState } from './types/state';
import { SchemaReturn as ConfigSchemaType } from './config/schema-type'; import { SchemaReturn as ConfigSchemaType } from './config/schema-type';
import log from './lib/supervisor-console';
const REPORT_SUCCESS_DELAY = 1000; const REPORT_SUCCESS_DELAY = 1000;
const MAX_REPORT_RETRY_DELAY = 60000; const MAX_REPORT_RETRY_DELAY = 60000;
@ -143,7 +145,7 @@ export class APIBinder {
); );
if (unmanaged) { if (unmanaged) {
console.log('Unmanaged mode is set, skipping API client initialization'); log.debug('Unmanaged mode is set, skipping API client initialization');
return; return;
} }
@ -167,11 +169,11 @@ export class APIBinder {
if (!exists) { if (!exists) {
return; return;
} }
console.log('Migration backup detected'); log.info('Migration backup detected');
const targetState = await this.getTargetState(); const targetState = await this.getTargetState();
await this.deviceState.restoreBackup(targetState); await this.deviceState.restoreBackup(targetState);
} catch (err) { } catch (err) {
console.log('Error restoring migration backup, retrying: ', err); log.error(`Error restoring migration backup, retrying: ${err}`);
await Bluebird.delay(retryDelay); await Bluebird.delay(retryDelay);
return this.loadBackupFromMigration(retryDelay); return this.loadBackupFromMigration(retryDelay);
@ -188,7 +190,7 @@ export class APIBinder {
const { unmanaged, bootstrapRetryDelay } = conf; const { unmanaged, bootstrapRetryDelay } = conf;
if (unmanaged) { if (unmanaged) {
console.log('Unmanaged mode is set, skipping API binder initialization'); log.info('Unmanaged mode is set, skipping API binder initialization');
// If we are offline because there is no apiEndpoint, there's a chance // If we are offline because there is no apiEndpoint, there's a chance
// we've went through a deprovision. We need to set the initialConfigReported // we've went through a deprovision. We need to set the initialConfigReported
// value to '', to ensure that when we do re-provision, we'll report // value to '', to ensure that when we do re-provision, we'll report
@ -199,7 +201,7 @@ export class APIBinder {
return; return;
} }
console.log('Ensuring device is provisioned'); log.debug('Ensuring device is provisioned');
await this.provisionDevice(); await this.provisionDevice();
const conf2 = await this.config.getMany([ const conf2 = await this.config.getMany([
'initialConfigReported', 'initialConfigReported',
@ -210,17 +212,17 @@ export class APIBinder {
// Either we haven't reported our initial config or we've been re-provisioned // Either we haven't reported our initial config or we've been re-provisioned
if (apiEndpoint !== initialConfigReported) { if (apiEndpoint !== initialConfigReported) {
console.log('Reporting initial configuration'); log.info('Reporting initial configuration');
await this.reportInitialConfig(apiEndpoint, bootstrapRetryDelay); await this.reportInitialConfig(apiEndpoint, bootstrapRetryDelay);
} }
console.log('Starting current state report'); log.debug('Starting current state report');
await this.startCurrentStateReport(); await this.startCurrentStateReport();
await this.loadBackupFromMigration(bootstrapRetryDelay); await this.loadBackupFromMigration(bootstrapRetryDelay);
this.readyForUpdates = true; this.readyForUpdates = true;
console.log('Starting target state poll'); log.debug('Starting target state poll');
this.startTargetStatePoll(); this.startTargetStatePoll();
} }
@ -506,7 +508,7 @@ export class APIBinder {
// We don't want this to be classed as a report error, as this will cause // We don't want this to be classed as a report error, as this will cause
// the watchdog to kill the supervisor - and killing the supervisor will // the watchdog to kill the supervisor - and killing the supervisor will
// not help in this situation // not help in this situation
console.error( log.error(
`Non-200 response from API! Status code: ${e.statusCode} - message: ${ `Non-200 response from API! Status code: ${e.statusCode} - message: ${
e.message e.message
}`, }`,
@ -564,7 +566,7 @@ export class APIBinder {
} }
}) })
.tapCatch(err => { .tapCatch(err => {
console.error(`Failed to get target state for device: ${err}`); log.error(`Failed to get target state for device: ${err}`);
}) })
.finally(() => { .finally(() => {
this.lastTargetStateFetch = process.hrtime(); this.lastTargetStateFetch = process.hrtime();
@ -645,8 +647,7 @@ export class APIBinder {
// task has been completed // task has been completed
await this.config.remove('pinDevice'); await this.config.remove('pinDevice');
} catch (e) { } catch (e) {
console.log('Could not pin device to release!'); log.error(`Could not pin device to release! ${e}`);
console.log('Error: ', e);
throw e; throw e;
} }
} }
@ -713,7 +714,7 @@ export class APIBinder {
try { try {
await this.reportInitialEnv(apiEndpoint); await this.reportInitialEnv(apiEndpoint);
} catch (err) { } catch (err) {
console.error('Error reporting initial configuration, will retry', err); log.error('Error reporting initial configuration, will retry', err);
await Bluebird.delay(retryDelay); await Bluebird.delay(retryDelay);
await this.reportInitialConfig(apiEndpoint, retryDelay); await this.reportInitialConfig(apiEndpoint, retryDelay);
} }
@ -791,11 +792,11 @@ export class APIBinder {
): Promise<Device> { ): Promise<Device> {
try { try {
const device = await this.exchangeKeyAndGetDevice(opts); const device = await this.exchangeKeyAndGetDevice(opts);
console.log('Key exchange succeeded'); log.debug('Key exchange succeeded');
return device; return device;
} catch (e) { } catch (e) {
if (e instanceof ExchangeKeyError) { if (e instanceof ExchangeKeyError) {
console.log('Exchanging key failed, re-registering...'); log.error('Exchanging key failed, re-registering...');
await this.config.regenerateRegistrationFields(); await this.config.regenerateRegistrationFields();
} }
throw e; throw e;
@ -804,7 +805,6 @@ export class APIBinder {
private async provision() { private async provision() {
let device: Device | null = null; let device: Device | null = null;
// FIXME: Config typing
const opts = await this.config.get('provisioningOptions'); const opts = await this.config.get('provisioningOptions');
if ( if (
opts.registered_at == null || opts.registered_at == null ||
@ -812,17 +812,17 @@ export class APIBinder {
opts.provisioningApiKey != null opts.provisioningApiKey != null
) { ) {
if (opts.registered_at != null && opts.deviceId == null) { if (opts.registered_at != null && opts.deviceId == null) {
console.log( log.debug(
'Device is registered but no device id available, attempting key exchange', 'Device is registered but no device id available, attempting key exchange',
); );
device = (await this.exchangeKeyAndGetDeviceOrRegenerate(opts)) || null; device = (await this.exchangeKeyAndGetDeviceOrRegenerate(opts)) || null;
} else if (opts.registered_at == null) { } else if (opts.registered_at == null) {
console.log('New device detected. Provisioning...'); log.info('New device detected. Provisioning...');
try { try {
device = await deviceRegister.register(opts).timeout(opts.apiTimeout); device = await deviceRegister.register(opts).timeout(opts.apiTimeout);
} catch (err) { } catch (err) {
if (DuplicateUuidError(err)) { if (DuplicateUuidError(err)) {
console.log('UUID already registered, trying a key exchange'); log.debug('UUID already registered, trying a key exchange');
device = await this.exchangeKeyAndGetDeviceOrRegenerate(opts); device = await this.exchangeKeyAndGetDeviceOrRegenerate(opts);
} else { } else {
throw err; throw err;
@ -830,7 +830,7 @@ export class APIBinder {
} }
opts.registered_at = Date.now(); opts.registered_at = Date.now();
} else if (opts.provisioningApiKey != null) { } else if (opts.provisioningApiKey != null) {
console.log( log.debug(
'Device is registered but we still have an apiKey, attempting key exchange', 'Device is registered but we still have an apiKey, attempting key exchange',
); );
device = await this.exchangeKeyAndGetDevice(opts); device = await this.exchangeKeyAndGetDevice(opts);
@ -864,12 +864,12 @@ export class APIBinder {
if (pinValue != null) { if (pinValue != null) {
if (pinValue.app == null || pinValue.commit == null) { if (pinValue.app == null || pinValue.commit == null) {
console.log( log.error(
`Malformed pinDevice fields in supervisor database: ${pinValue}`, `Malformed pinDevice fields in supervisor database: ${pinValue}`,
); );
return; return;
} }
console.log('Attempting to pin device to preloaded release...'); log.info('Attempting to pin device to preloaded release...');
return this.pinDevice(pinValue); return this.pinDevice(pinValue);
} }
} }
@ -932,7 +932,7 @@ export class APIBinder {
.catch(_.noop); .catch(_.noop);
res.sendStatus(204); res.sendStatus(204);
} else { } else {
console.log( log.debug(
'Ignoring update notification because instant updates are disabled', 'Ignoring update notification because instant updates are disabled',
); );
res.sendStatus(202); res.sendStatus(202);

View File

@ -260,7 +260,7 @@ module.exports = class ApplicationManager extends EventEmitter
dependent[appId].images[image.imageId] = _.pick(image, [ 'status' ]) dependent[appId].images[image.imageId] = _.pick(image, [ 'status' ])
dependent[appId].images[image.imageId].download_progress = image.downloadProgress dependent[appId].images[image.imageId].download_progress = image.downloadProgress
else else
console.log('Ignoring legacy dependent image', image) log.debug('Ignoring legacy dependent image', image)
obj = { local: apps, dependent } obj = { local: apps, dependent }
obj.commit = currentCommit obj.commit = currentCommit

View File

@ -18,6 +18,8 @@ import * as validation from '../lib/validation';
import Logger from '../logger'; import Logger from '../logger';
import { ImageDownloadBackoffError } from './errors'; import { ImageDownloadBackoffError } from './errors';
import log from '../lib/supervisor-console';
interface ImageEvents { interface ImageEvents {
change: void; change: void;
} }
@ -452,7 +454,7 @@ export class Images extends (EventEmitter as new () => ImageEventEmitter) {
public async cleanup() { public async cleanup() {
const images = await this.getImagesForCleanup(); const images = await this.getImagesForCleanup();
for (const image of images) { for (const image of images) {
console.log(`Cleaning up ${image}`); log.debug(`Cleaning up ${image}`);
try { try {
await this.docker.getImage(image).remove({ force: true }); await this.docker.getImage(image).remove({ force: true });
delete this.imageCleanupFailures[image]; delete this.imageCleanupFailures[image];

View File

@ -8,6 +8,8 @@ import { ENOENT, NotFoundError } from '../lib/errors';
import { Logger } from '../logger'; import { Logger } from '../logger';
import { Network, NetworkOptions } from './network'; import { Network, NetworkOptions } from './network';
import log from '../lib/supervisor-console';
export class NetworkManager { export class NetworkManager {
private docker: Docker; private docker: Docker;
private logger: Logger; private logger: Logger;
@ -101,7 +103,7 @@ export class NetworkManager {
} }
}) })
.catch(NotFoundError, () => { .catch(NotFoundError, () => {
console.log(`Creating ${constants.supervisorNetworkInterface} network`); log.debug(`Creating ${constants.supervisorNetworkInterface} network`);
return Bluebird.resolve( return Bluebird.resolve(
this.docker.createNetwork({ this.docker.createNetwork({
Name: constants.supervisorNetworkInterface, Name: constants.supervisorNetworkInterface,

View File

@ -2,6 +2,8 @@ import * as _ from 'lodash';
import { ConfigMap, ServiceComposeConfig } from './types/service'; import { ConfigMap, ServiceComposeConfig } from './types/service';
import log from '../lib/supervisor-console';
// TODO: Generate these fields from the interface we define // TODO: Generate these fields from the interface we define
// in service-types. // in service-types.
const supportedComposeFields = [ const supportedComposeFields = [
@ -71,10 +73,8 @@ export function sanitiseComposeConfig(
}) as ServiceComposeConfig; }) as ServiceComposeConfig;
if (filtered.length > 0) { if (filtered.length > 0) {
console.log( log.warn(
`Warning: Ignoring unsupported or unknown compose fields: ${filtered.join( `Ignoring unsupported or unknown compose fields: ${filtered.join(', ')}`,
', ',
)}`,
); );
} }

View File

@ -22,6 +22,8 @@ import { checkInt, isValidDeviceName } from '../lib/validation';
import { Service } from './service'; import { Service } from './service';
import { serviceNetworksToDockerNetworks } from './utils'; import { serviceNetworksToDockerNetworks } from './utils';
import log from '../lib/supervisor-console';
interface ServiceConstructOpts { interface ServiceConstructOpts {
docker: Docker; docker: Docker;
logger: Logger; logger: Logger;
@ -388,7 +390,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
}); });
stream.on('error', e => { stream.on('error', e => {
console.error(`Error on docker events stream:`, e); log.error(`Error on docker events stream:`, e);
}); });
const parser = JSONStream.parse(); const parser = JSONStream.parse();
parser.on('data', async (data: { status: string; id: string }) => { parser.on('data', async (data: { status: string; id: string }) => {
@ -434,7 +436,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
} }
} }
} catch (e) { } catch (e) {
console.error('Error on docker event:', e, e.stack); log.error('Error on docker event:', e, e.stack);
} }
} }
} }
@ -443,7 +445,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
parser parser
.on('error', (e: Error) => { .on('error', (e: Error) => {
console.error('Error on docker events stream:', e); log.error('Error on docker events stream:', e);
reject(e); reject(e);
}) })
.on('end', resolve); .on('end', resolve);
@ -453,7 +455,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
Bluebird.resolve(listen()) Bluebird.resolve(listen())
.catch(e => { .catch(e => {
console.error('Error listening to events:', e, e.stack); log.error('Error listening to events:', e, e.stack);
}) })
.finally(() => { .finally(() => {
this.listening = false; this.listening = false;
@ -645,7 +647,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
await Bluebird.delay(pollInterval); await Bluebird.delay(pollInterval);
return wait(); return wait();
} else { } else {
console.log( log.info(
`Handover timeout has passed, assuming handover was completed for service ${ `Handover timeout has passed, assuming handover was completed for service ${
service.serviceName service.serviceName
}`, }`,
@ -653,14 +655,14 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
} }
}); });
console.log( log.info(
`Waiting for handover to be completed for service: ${ `Waiting for handover to be completed for service: ${
service.serviceName service.serviceName
}`, }`,
); );
return wait().then(() => { return wait().then(() => {
console.log(`Handover complete for service ${service.serviceName}`); log.success(`Handover complete for service ${service.serviceName}`);
}); });
} }
} }

View File

@ -21,6 +21,8 @@ import * as constants from '../lib/constants';
import * as updateLock from '../lib/update-lock'; import * as updateLock from '../lib/update-lock';
import { sanitiseComposeConfig } from './sanitise'; import { sanitiseComposeConfig } from './sanitise';
import log from '../lib/supervisor-console';
export class Service { export class Service {
public appId: number | null; public appId: number | null;
public imageId: number | null; public imageId: number | null;
@ -138,13 +140,13 @@ export class Service {
// Check for unsupported networkMode entries // Check for unsupported networkMode entries
if (config.networkMode != null) { if (config.networkMode != null) {
if (/service:(\s*)?.+/.test(config.networkMode)) { if (/service:(\s*)?.+/.test(config.networkMode)) {
console.log( log.warn(
'Warning: A network_mode referencing a service is not yet supported. Ignoring.', 'A network_mode referencing a service is not yet supported. Ignoring.',
); );
delete config.networkMode; delete config.networkMode;
} else if (/container:(\s*)?.+/.test(config.networkMode)) { } else if (/container:(\s*)?.+/.test(config.networkMode)) {
console.log( log.warn(
'Warning: A network_mode referencing a container is not supported. Ignoring.', 'A network_mode referencing a container is not supported. Ignoring.',
); );
delete config.networkMode; delete config.networkMode;
} }
@ -317,8 +319,11 @@ export class Service {
if (config.cpus != null) { if (config.cpus != null) {
config.cpus = Math.round(Number(config.cpus) * 10 ** 9); config.cpus = Math.round(Number(config.cpus) * 10 ** 9);
if (_.isNaN(config.cpus)) { if (_.isNaN(config.cpus)) {
console.log('Warning: config.cpus value cannot be parsed. Ignoring.'); log.warn(
console.log(` Value: ${config.cpus}`); `config.cpus value cannot be parsed. Ignoring.\n Value:${
config.cpus
}`,
);
config.cpus = undefined; config.cpus = undefined;
} }
} }
@ -666,7 +671,7 @@ export class Service {
if (!(sameConfig && sameNetworks)) { if (!(sameConfig && sameNetworks)) {
// Add some console output for why a service is not matching // Add some console output for why a service is not matching
// so that if we end up in a restart loop, we know exactly why // so that if we end up in a restart loop, we know exactly why
console.log( log.debug(
`Replacing container for service ${ `Replacing container for service ${
this.serviceName this.serviceName
} because of config changes:`, } because of config changes:`,
@ -680,14 +685,14 @@ export class Service {
() => 'hidden', () => 'hidden',
); );
} }
console.log(' Non-array fields: ', JSON.stringify(diffObj)); log.debug(' Non-array fields: ', JSON.stringify(diffObj));
} }
if (differentArrayFields.length > 0) { if (differentArrayFields.length > 0) {
console.log(' Array Fields: ', differentArrayFields.join(',')); log.debug(' Array Fields: ', differentArrayFields.join(','));
} }
if (!sameNetworks) { if (!sameNetworks) {
console.log(' Network changes detected'); log.debug(' Network changes detected');
} }
} }
return sameNetworks && sameConfig; return sameNetworks && sameConfig;
@ -725,10 +730,9 @@ export class Service {
if (!path.isAbsolute(bindSource)) { if (!path.isAbsolute(bindSource)) {
const match = bindSource.match(/[0-9]+_(.+)/); const match = bindSource.match(/[0-9]+_(.+)/);
if (match == null) { if (match == null) {
console.log( log.error(
'Error: There was an error parsing a volume bind source, ignoring.', `Error: There was an error parsing a volume bind source, ignoring.\nBind source: ${bindSource}`,
); );
console.log(' bind source: ', bindSource);
return null; return null;
} }
return match[1]; return match[1];
@ -914,7 +918,7 @@ export class Service {
} }
volumes.push(volumeDef); volumes.push(volumeDef);
} else { } else {
console.log(`Ignoring invalid bind mount ${volume}`); log.warn(`Ignoring invalid bind mount ${volume}`);
} }
} else { } else {
volumes.push(volume); volumes.push(volume);

View File

@ -16,6 +16,8 @@ import {
ServiceHealthcheck, ServiceHealthcheck,
} from './types/service'; } from './types/service';
import log from '../lib/supervisor-console';
export function camelCaseConfig( export function camelCaseConfig(
literalConfig: ConfigMap, literalConfig: ConfigMap,
): ServiceComposeConfig { ): ServiceComposeConfig {
@ -80,9 +82,7 @@ export function createRestartPolicy(name?: string): string {
// Ensure that name is a string, otherwise the below could // Ensure that name is a string, otherwise the below could
// throw // throw
if (!_.isString(name)) { if (!_.isString(name)) {
console.log( log.warn(`Non-string argument for restart field: ${name} - ignoring.`);
`Warning: Non-string argument for restart field: ${name} - ignoring.`,
);
return 'always'; return 'always';
} }

View File

@ -8,6 +8,8 @@ import * as fsUtils from '../lib/fs-utils';
const childProcess: any = Promise.promisifyAll(childProcessSync); const childProcess: any = Promise.promisifyAll(childProcessSync);
import log from '../lib/supervisor-console';
export interface ConfigOptions { export interface ConfigOptions {
[key: string]: string | string[]; [key: string]: string | string[];
} }
@ -147,9 +149,7 @@ export class RPiConfigBackend extends DeviceConfigBackend {
const [, key, value] = keyValue; const [, key, value] = keyValue;
conf[key] = value; conf[key] = value;
} else { } else {
console.log( log.warn(`Could not parse config.txt entry: ${configStr}. Ignoring.`);
`Warning - Could not parse config.txt entry: ${configStr}. Ignoring.`,
);
} }
} }
@ -362,7 +362,7 @@ export class ExtlinuxConfigBackend extends DeviceConfigBackend {
for (const line of lines) { for (const line of lines) {
const match = line.match(/^\s*(\w+)\s?(.*)$/); const match = line.match(/^\s*(\w+)\s?(.*)$/);
if (match == null) { if (match == null) {
console.log('Warning - Could not read extlinux entry: ${line}'); log.warn(`Could not read extlinux entry: ${line}`);
continue; continue;
} }
let directive = match[1].toUpperCase(); let directive = match[1].toUpperCase();

View File

@ -10,6 +10,8 @@ import * as constants from '../lib/constants';
import { writeAndSyncFile, writeFileAtomic } from '../lib/fs-utils'; import { writeAndSyncFile, writeFileAtomic } from '../lib/fs-utils';
import * as osRelease from '../lib/os-release'; import * as osRelease from '../lib/os-release';
import log from '../lib/supervisor-console';
export default class ConfigJsonConfigBackend { export default class ConfigJsonConfigBackend {
private readLockConfigJson: () => Promise.Disposer<() => void>; private readLockConfigJson: () => Promise.Disposer<() => void>;
private writeLockConfigJson: () => Promise.Disposer<() => void>; private writeLockConfigJson: () => Promise.Disposer<() => void>;
@ -88,7 +90,7 @@ export default class ConfigJsonConfigBackend {
public path(): Promise<string> { public path(): Promise<string> {
return this.pathOnHost().catch(err => { return this.pathOnHost().catch(err => {
console.error(err.message); log.error('There was an error detecting the config.json path', err);
return constants.configJsonNonAtomicPath; return constants.configJsonNonAtomicPath;
}); });
} }
@ -97,7 +99,7 @@ export default class ConfigJsonConfigBackend {
let atomicWritePossible = true; let atomicWritePossible = true;
return this.pathOnHost() return this.pathOnHost()
.catch(err => { .catch(err => {
console.error(err.message); log.error('There was an error detecting the config.json path', err);
atomicWritePossible = false; atomicWritePossible = false;
return constants.configJsonNonAtomicPath; return constants.configJsonNonAtomicPath;
}) })

View File

@ -12,6 +12,7 @@ import {
} from '../lib/messages'; } from '../lib/messages';
import { doPurge, doRestart, serviceAction } from './common'; import { doPurge, doRestart, serviceAction } from './common';
import log from '../lib/supervisor-console';
import supervisorVersion = require('../lib/supervisor-version'); import supervisorVersion = require('../lib/supervisor-version');
export function createV2Api(router: Router, applications: ApplicationManager) { export function createV2Api(router: Router, applications: ApplicationManager) {
@ -193,8 +194,11 @@ export function createV2Api(router: Router, applications: ApplicationManager) {
images.forEach(img => { images.forEach(img => {
const appName = appNameById[img.appId]; const appName = appNameById[img.appId];
if (appName == null) { if (appName == null) {
console.log('Image found for unknown application!'); log.warn(
console.log(' Image: ', JSON.stringify(img)); `Image found for unknown application!\nImage: ${JSON.stringify(
img,
)}`,
);
return; return;
} }

View File

@ -22,6 +22,8 @@ updateLock = require './lib/update-lock'
{ DeviceConfig } = require './device-config' { DeviceConfig } = require './device-config'
ApplicationManager = require './application-manager' ApplicationManager = require './application-manager'
{ log } = require './lib/supervisor-console'
validateLocalState = (state) -> validateLocalState = (state) ->
if state.name? if state.name?
throw new Error('Invalid device name') if not validation.isValidShortText(state.name) throw new Error('Invalid device name') if not validation.isValidShortText(state.name)
@ -120,7 +122,7 @@ module.exports = class DeviceState extends EventEmitter
@deviceConfig = new DeviceConfig({ @db, @config, @logger }) @deviceConfig = new DeviceConfig({ @db, @config, @logger })
@applications = new ApplicationManager({ @config, @logger, @db, @eventTracker, deviceState: this }) @applications = new ApplicationManager({ @config, @logger, @db, @eventTracker, deviceState: this })
@on 'error', (err) -> @on 'error', (err) ->
console.error('Error in deviceState: ', err, err.stack) log.error('deviceState error: ', err)
@_currentVolatile = {} @_currentVolatile = {}
@_writeLock = updateLock.writeLock @_writeLock = updateLock.writeLock
@_readLock = updateLock.readLock @_readLock = updateLock.readLock
@ -134,9 +136,9 @@ module.exports = class DeviceState extends EventEmitter
@on 'apply-target-state-end', (err) -> @on 'apply-target-state-end', (err) ->
if err? if err?
if not (err instanceof UpdatesLockedError) if not (err instanceof UpdatesLockedError)
console.log("Apply error #{err}") log.error('Device state apply error', err)
else else
console.log('Apply success!') log.success('Device state apply success')
@applications.on('change', @reportCurrentState) @applications.on('change', @reportCurrentState)
healthcheck: => healthcheck: =>
@ -149,23 +151,23 @@ module.exports = class DeviceState extends EventEmitter
return applyTargetHealthy return applyTargetHealthy
migrateLegacyApps: (balenaApi) => migrateLegacyApps: (balenaApi) =>
console.log('Migrating ids for legacy app...') log.info('Migrating ids for legacy app...')
@db.models('app').select() @db.models('app').select()
.then (apps) => .then (apps) =>
if apps.length == 0 if apps.length == 0
console.log('No app to migrate') log.debug('No app to migrate')
return return
Promise.map apps, (app) => Promise.map apps, (app) =>
services = JSON.parse(app.services) services = JSON.parse(app.services)
# Check there's a main service, with legacy-container set # Check there's a main service, with legacy-container set
if services.length != 1 if services.length != 1
console.log("App doesn't have a single service, ignoring") log.debug("App doesn't have a single service, ignoring")
return return
service = services[0] service = services[0]
if !service.labels['io.resin.legacy-container'] and !service.labels['io.balena.legacy-container'] if !service.labels['io.resin.legacy-container'] and !service.labels['io.balena.legacy-container']
console.log('Service is not marked as legacy, ignoring') log.debug('Service is not marked as legacy, ignoring')
return return
console.log("Getting release #{app.commit} for app #{app.appId} from API") log.debug("Getting release #{app.commit} for app #{app.appId} from API")
balenaApi.get( balenaApi.get(
resource: 'release' resource: 'release'
options: options:
@ -179,7 +181,7 @@ module.exports = class DeviceState extends EventEmitter
) )
.then (releasesFromAPI) => .then (releasesFromAPI) =>
if releasesFromAPI.length == 0 if releasesFromAPI.length == 0
console.log("No compatible releases found in API, removing #{app.appId} from target state") log.warn("No compatible releases found in API, removing #{app.appId} from target state")
return @db.models('app').where({ appId: app.appId }).del() return @db.models('app').where({ appId: app.appId }).del()
release = releasesFromAPI[0] release = releasesFromAPI[0]
releaseId = release.id releaseId = release.id
@ -189,8 +191,7 @@ module.exports = class DeviceState extends EventEmitter
imageUrl = image.is_stored_at__image_location imageUrl = image.is_stored_at__image_location
if image.content_hash if image.content_hash
imageUrl += "@#{image.content_hash}" imageUrl += "@#{image.content_hash}"
console.log("Found a release with releaseId #{releaseId}, imageId #{imageId}, serviceId #{serviceId}") log.debug("Found a release with releaseId #{releaseId}, imageId #{imageId}, serviceId #{serviceId}\nImage location is #{imageUrl}")
console.log("Image location is #{imageUrl}")
Promise.join( Promise.join(
@applications.docker.getImage(service.image).inspect().catchReturn(NotFoundError, null) @applications.docker.getImage(service.image).inspect().catchReturn(NotFoundError, null)
@db.models('image').where(name: service.image).select() @db.models('image').where(name: service.image).select()
@ -198,13 +199,13 @@ module.exports = class DeviceState extends EventEmitter
@db.transaction (trx) -> @db.transaction (trx) ->
Promise.try -> Promise.try ->
if imagesFromDB.length > 0 if imagesFromDB.length > 0
console.log('Deleting existing image entry in db') log.debug('Deleting existing image entry in db')
trx('image').where(name: service.image).del() trx('image').where(name: service.image).del()
else else
console.log('No image in db to delete') log.debug('No image in db to delete')
.then -> .then ->
if imageFromDocker? if imageFromDocker?
console.log('Inserting fixed image entry in db') log.debug('Inserting fixed image entry in db')
newImage = { newImage = {
name: imageUrl, name: imageUrl,
appId: app.appId, appId: app.appId,
@ -217,7 +218,7 @@ module.exports = class DeviceState extends EventEmitter
} }
trx('image').insert(newImage) trx('image').insert(newImage)
else else
console.log('Image is not downloaded, so not saving it to db') log.debug('Image is not downloaded, so not saving it to db')
.then -> .then ->
service.image = imageUrl service.image = imageUrl
service.serviceID = serviceId service.serviceID = serviceId
@ -227,7 +228,8 @@ module.exports = class DeviceState extends EventEmitter
delete service.labels['io.balena.legacy-container'] delete service.labels['io.balena.legacy-container']
app.services = JSON.stringify([ service ]) app.services = JSON.stringify([ service ])
app.releaseId = releaseId app.releaseId = releaseId
console.log('Updating app entry in db') log.debug('Updating app entry in db')
log.success('Successfully migrated legacy applciation')
trx('app').update(app).where({ appId: app.appId }) trx('app').update(app).where({ appId: app.appId })
) )
@ -236,10 +238,10 @@ module.exports = class DeviceState extends EventEmitter
# We also need to get the releaseId, serviceId, imageId and updated image URL # We also need to get the releaseId, serviceId, imageId and updated image URL
@migrateLegacyApps(balenaApi) @migrateLegacyApps(balenaApi)
.then => .then =>
console.log('Killing legacy containers') log.debug('Killing legacy containers')
@applications.services.killAllLegacy() @applications.services.killAllLegacy()
.then => .then =>
console.log('Migrating legacy app volumes') log.debug('Migrating legacy app volumes')
@applications.getTargetApps() @applications.getTargetApps()
.then(_.keys) .then(_.keys)
.map (appId) => .map (appId) =>
@ -269,7 +271,7 @@ module.exports = class DeviceState extends EventEmitter
@saveInitialConfig() @saveInitialConfig()
.then => .then =>
@initNetworkChecks(conf) @initNetworkChecks(conf)
console.log('Reporting initial state, supervisor version and API info') log.info('Reporting initial state, supervisor version and API info')
@reportCurrentState( @reportCurrentState(
api_port: conf.listenPort api_port: conf.listenPort
api_secret: conf.apiSecret api_secret: conf.apiSecret
@ -292,7 +294,7 @@ module.exports = class DeviceState extends EventEmitter
.finally => .finally =>
@config.set({ targetStateSet: 'true' }) @config.set({ targetStateSet: 'true' })
else else
console.log('Skipping preloading') log.debug('Skipping preloading')
if conf.provisioned and !_.isEmpty(targetApps) if conf.provisioned and !_.isEmpty(targetApps)
# If we're in this case, it's because we've updated from an older supervisor # If we're in this case, it's because we've updated from an older supervisor
# and we need to mark that the target state has been set so that # and we need to mark that the target state has been set so that
@ -309,7 +311,7 @@ module.exports = class DeviceState extends EventEmitter
@config.on 'change', (changedConfig) -> @config.on 'change', (changedConfig) ->
if changedConfig.connectivityCheckEnabled? if changedConfig.connectivityCheckEnabled?
network.enableConnectivityCheck(changedConfig.connectivityCheckEnabled) network.enableConnectivityCheck(changedConfig.connectivityCheckEnabled)
console.log('Starting periodic check for IP addresses') log.debug('Starting periodic check for IP addresses')
network.startIPAddressUpdate() (addresses) => network.startIPAddressUpdate() (addresses) =>
@reportCurrentState( @reportCurrentState(
ip_address: addresses.join(' ') ip_address: addresses.join(' ')
@ -441,7 +443,7 @@ module.exports = class DeviceState extends EventEmitter
if !s.isDirectory() if !s.isDirectory()
throw new Error("Invalid backup: #{volumeName} is not a directory") throw new Error("Invalid backup: #{volumeName} is not a directory")
if volumes[volumeName]? if volumes[volumeName]?
console.log("Creating volume #{volumeName} from backup") log.debug("Creating volume #{volumeName} from backup")
# If the volume exists (from a previous incomplete run of this restoreBackup), we delete it first # If the volume exists (from a previous incomplete run of this restoreBackup), we delete it first
@applications.volumes.get({ appId, name: volumeName }) @applications.volumes.get({ appId, name: volumeName })
.then => .then =>
@ -457,14 +459,14 @@ module.exports = class DeviceState extends EventEmitter
rimraf(path.join(constants.rootMountPoint, 'mnt/data', constants.migrationBackupFile)) rimraf(path.join(constants.rootMountPoint, 'mnt/data', constants.migrationBackupFile))
loadTargetFromFile: (appsPath) -> loadTargetFromFile: (appsPath) ->
console.log('Attempting to load preloaded apps...') log.info('Attempting to load preloaded apps...')
appsPath ?= constants.appsJsonPath appsPath ?= constants.appsJsonPath
fs.readFileAsync(appsPath, 'utf8') fs.readFileAsync(appsPath, 'utf8')
.then(JSON.parse) .then(JSON.parse)
.then (stateFromFile) => .then (stateFromFile) =>
if _.isArray(stateFromFile) if _.isArray(stateFromFile)
# This is a legacy apps.json # This is a legacy apps.json
console.log('Legacy apps.json detected') log.debug('Legacy apps.json detected')
return @_convertLegacyAppsJson(stateFromFile) return @_convertLegacyAppsJson(stateFromFile)
else else
return stateFromFile return stateFromFile
@ -503,11 +505,11 @@ module.exports = class DeviceState extends EventEmitter
local: stateFromFile local: stateFromFile
}) })
.then => .then =>
console.log('Preloading complete') log.success('Preloading complete')
if stateFromFile.pinDevice if stateFromFile.pinDevice
# multi-app warning! # multi-app warning!
# The following will need to be changed once running multiple applications is possible # The following will need to be changed once running multiple applications is possible
console.log('Device will be pinned') log.debug('Device will be pinned')
if commitToPin? and appToPin? if commitToPin? and appToPin?
@config.set @config.set
pinDevice: { pinDevice: {
@ -519,7 +521,7 @@ module.exports = class DeviceState extends EventEmitter
# on host, the docker daemon creates an empty directory when # on host, the docker daemon creates an empty directory when
# the bind mount is added # the bind mount is added
.catch ENOENT, EISDIR, -> .catch ENOENT, EISDIR, ->
console.log('No apps.json file present, skipping preload') log.debug('No apps.json file present, skipping preload')
.catch (err) => .catch (err) =>
@eventTracker.track('Loading preloaded apps failed', { error: err }) @eventTracker.track('Loading preloaded apps failed', { error: err })
@ -580,16 +582,16 @@ module.exports = class DeviceState extends EventEmitter
@reportCurrentState(update_failed: true) @reportCurrentState(update_failed: true)
if @scheduledApply? if @scheduledApply?
if not (err instanceof UpdatesLockedError) if not (err instanceof UpdatesLockedError)
console.log("Updating failed, but there's another update scheduled immediately: ", err) log.error("Updating failed, but there's another update scheduled immediately: ", err)
else else
delay = Math.min((2 ** @failedUpdates) * constants.backoffIncrement, @maxPollTime) delay = Math.min((2 ** @failedUpdates) * constants.backoffIncrement, @maxPollTime)
# If there was an error then schedule another attempt briefly in the future. # If there was an error then schedule another attempt briefly in the future.
if err instanceof UpdatesLockedError if err instanceof UpdatesLockedError
message = "Updates are locked, retrying in #{prettyMs(delay, compact: true)}..." message = "Updates are locked, retrying in #{prettyMs(delay, compact: true)}..."
@logger.logSystemMessage(message, {}, 'updateLocked', false) @logger.logSystemMessage(message, {}, 'updateLocked', false)
console.log(message) log.info(message)
else else
console.log('Scheduling another update attempt due to failure: ', delay, err) log.error("Scheduling another update attempt in #{delay}ms due to failure: ", err)
@triggerApplyTarget({ force, delay, initial }) @triggerApplyTarget({ force, delay, initial })
applyTarget: ({ force = false, initial = false, intermediate = false, skipLock = false, nextDelay = 200, retryCount = 0 } = {}) => applyTarget: ({ force = false, initial = false, intermediate = false, skipLock = false, nextDelay = 200, retryCount = 0 } = {}) =>
@ -627,7 +629,7 @@ module.exports = class DeviceState extends EventEmitter
if _.isEmpty(steps) if _.isEmpty(steps)
@emitAsync('apply-target-state-end', null) @emitAsync('apply-target-state-end', null)
if !intermediate if !intermediate
console.log('Finished applying target state') log.debug('Finished applying target state')
@applications.timeSpentFetching = 0 @applications.timeSpentFetching = 0
@failedUpdates = 0 @failedUpdates = 0
@lastSuccessfulUpdate = Date.now() @lastSuccessfulUpdate = Date.now()
@ -685,7 +687,7 @@ module.exports = class DeviceState extends EventEmitter
Promise.delay(delay) Promise.delay(delay)
.then => .then =>
@lastApplyStart = process.hrtime() @lastApplyStart = process.hrtime()
console.log('Applying target state') log.info('Applying target state')
@applyTarget({ force, initial }) @applyTarget({ force, initial })
.finally => .finally =>
@applyInProgress = false @applyInProgress = false

View File

@ -5,6 +5,7 @@ import * as memoizee from 'memoizee';
import Mixpanel = require('mixpanel'); import Mixpanel = require('mixpanel');
import Config from './config'; import Config from './config';
import log from './lib/supervisor-console';
import supervisorVersion = require('./lib/supervisor-version'); import supervisorVersion = require('./lib/supervisor-version');
export type EventTrackProperties = Dictionary<any>; export type EventTrackProperties = Dictionary<any>;
@ -63,16 +64,14 @@ export class EventTracker {
}); });
this.isEnabled = await config.get('mixpanelReport'); this.isEnabled = await config.get('mixpanelReport');
console.log( log.info(
`Mixpanel reporting is ${this.isEnabled ? 'enabled' : 'disabled'}`, `Mixpanel reporting is ${this.isEnabled ? 'enabled' : 'disabled'}`,
); );
config.on('change', conf => { config.on('change', conf => {
const mixpanelReport = conf.mixpanelReport; const mixpanelReport = conf.mixpanelReport;
if (mixpanelReport != null && mixpanelReport !== this.isEnabled) { if (mixpanelReport != null && mixpanelReport !== this.isEnabled) {
this.isEnabled = mixpanelReport; this.isEnabled = mixpanelReport;
console.log( log.info(`${mixpanelReport ? 'A' : 'Dea'}ctivating mixpanel reporting`);
`${mixpanelReport ? 'A' : 'Dea'}ctivating mixpanel reporting`,
);
} }
}); });
} }
@ -117,7 +116,7 @@ export class EventTracker {
); );
private logEvent(...args: string[]) { private logEvent(...args: string[]) {
console.log(...args); log.event(...args);
} }
private assignDefaultProperties( private assignDefaultProperties(

View File

@ -2,12 +2,14 @@ import * as _ from 'lodash';
import { EnvVarObject } from './types'; import { EnvVarObject } from './types';
import log from '../lib/supervisor-console';
export function envArrayToObject(env: string[]): EnvVarObject { export function envArrayToObject(env: string[]): EnvVarObject {
const toPair = (keyVal: string) => { const toPair = (keyVal: string) => {
const m = keyVal.match(/^([^=]+)=([^]*)$/); const m = keyVal.match(/^([^=]+)=([^]*)$/);
if (m == null) { if (m == null) {
console.log( log.warn(
`WARNING: Could not correctly parse env var ${keyVal}. ` + `Could not correctly parse env var ${keyVal}. ` +
'Please fix this var and recreate the container.', 'Please fix this var and recreate the container.',
); );
return [null, null]; return [null, null];

View File

@ -16,6 +16,8 @@ import {
import { request, requestLib, resumable } from './request'; import { request, requestLib, resumable } from './request';
import { EnvVarObject } from './types'; import { EnvVarObject } from './types';
import log from './supervisor-console';
export type FetchOptions = SchemaReturn<'fetchOptions'>; export type FetchOptions = SchemaReturn<'fetchOptions'>;
export type DeltaFetchOptions = FetchOptions & { export type DeltaFetchOptions = FetchOptions & {
deltaSourceId: string; deltaSourceId: string;
@ -77,11 +79,11 @@ export class DockerUtils extends DockerToolbelt {
const timeout = deltaOpts.deltaApplyTimeout; const timeout = deltaOpts.deltaApplyTimeout;
const log = (str: string) => const logFn = (str: string) =>
console.log(`delta([${serviceName}] ${deltaOpts.deltaSource}): ${str}`); log.debug(`delta([${serviceName}] ${deltaOpts.deltaSource}): ${str}`);
if (!_.includes([2, 3], deltaOpts.deltaVersion)) { if (!_.includes([2, 3], deltaOpts.deltaVersion)) {
log( logFn(
`Unsupported delta version: ${ `Unsupported delta version: ${
deltaOpts.deltaVersion deltaOpts.deltaVersion
}. Failling back to regular pull`, }. Failling back to regular pull`,
@ -92,12 +94,12 @@ export class DockerUtils extends DockerToolbelt {
// Since the supevisor never calls this function with a source anymore, // Since the supevisor never calls this function with a source anymore,
// this should never happen, but w ehandle it anyway // this should never happen, but w ehandle it anyway
if (deltaOpts.deltaSource == null) { if (deltaOpts.deltaSource == null) {
log('Falling back to regular pull due to lack of a delta source'); logFn('Falling back to regular pull due to lack of a delta source');
return this.fetchImageWithProgress(imgDest, deltaOpts, onProgress); return this.fetchImageWithProgress(imgDest, deltaOpts, onProgress);
} }
const docker = this; const docker = this;
log(`Starting delta to ${imgDest}`); logFn(`Starting delta to ${imgDest}`);
const [dstInfo, srcInfo] = await Promise.all([ const [dstInfo, srcInfo] = await Promise.all([
this.getRegistryAndName(imgDest), this.getRegistryAndName(imgDest),
@ -153,7 +155,7 @@ export class DockerUtils extends DockerToolbelt {
timeout, timeout,
resumeOpts, resumeOpts,
onProgress, onProgress,
log, logFn,
); );
break; break;
case 3: case 3:
@ -177,7 +179,7 @@ export class DockerUtils extends DockerToolbelt {
name, name,
token, token,
onProgress, onProgress,
log, logFn,
); );
break; break;
default: default:
@ -187,19 +189,19 @@ export class DockerUtils extends DockerToolbelt {
} }
} catch (e) { } catch (e) {
if (e instanceof OutOfSyncError) { if (e instanceof OutOfSyncError) {
log('Falling back to regular pull due to delta out of sync error'); logFn('Falling back to regular pull due to delta out of sync error');
return await this.fetchImageWithProgress( return await this.fetchImageWithProgress(
imgDest, imgDest,
deltaOpts, deltaOpts,
onProgress, onProgress,
); );
} else { } else {
log(`Delta failed with ${e}`); logFn(`Delta failed with ${e}`);
throw e; throw e;
} }
} }
log(`Delta applied successfully`); logFn(`Delta applied successfully`);
return id; return id;
} }
@ -228,7 +230,7 @@ export class DockerUtils extends DockerToolbelt {
try { try {
return envArrayToObject(_.get(inspect, ['Config', 'Env'], [])); return envArrayToObject(_.get(inspect, ['Config', 'Env'], []));
} catch (e) { } catch (e) {
console.log('Error getting env from image', e, e.stack); log.error('Error getting env from image', e);
return {}; return {};
} }
} }
@ -259,9 +261,9 @@ export class DockerUtils extends DockerToolbelt {
applyTimeout: number, applyTimeout: number,
opts: RsyncApplyOptions, opts: RsyncApplyOptions,
onProgress: ProgressCallback, onProgress: ProgressCallback,
log: (str: string) => void, logFn: (str: string) => void,
): Promise<string> { ): Promise<string> {
log('Applying rsync delta...'); logFn('Applying rsync delta...');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const req = resumable(Object.assign({ url: deltaUrl }, opts)); const req = resumable(Object.assign({ url: deltaUrl }, opts));
@ -280,14 +282,14 @@ export class DockerUtils extends DockerToolbelt {
reject(new Error('Invalid delta URL')); reject(new Error('Invalid delta URL'));
} else { } else {
const deltaStream = applyDelta(imgSrc, { const deltaStream = applyDelta(imgSrc, {
log, log: logFn,
timeout: applyTimeout, timeout: applyTimeout,
}); });
res res
.pipe(deltaStream) .pipe(deltaStream)
.on('id', id => resolve(`sha256:${id}`)) .on('id', id => resolve(`sha256:${id}`))
.on('error', err => { .on('error', err => {
log(`Delta stream emitted error: ${err}`); logFn(`Delta stream emitted error: ${err}`);
req.abort(); req.abort();
reject(err); reject(err);
}); });
@ -301,13 +303,13 @@ export class DockerUtils extends DockerToolbelt {
deltaImg: string, deltaImg: string,
token: string | null, token: string | null,
onProgress: ProgressCallback, onProgress: ProgressCallback,
log: (str: string) => void, logFn: (str: string) => void,
): Promise<string> { ): Promise<string> {
log('Applying balena delta...'); logFn('Applying balena delta...');
let auth: Dictionary<unknown> | undefined; let auth: Dictionary<unknown> | undefined;
if (token != null) { if (token != null) {
log('Using registry auth token'); logFn('Using registry auth token');
auth = { auth = {
authconfig: { authconfig: {
registrytoken: token, registrytoken: token,

View File

@ -2,6 +2,8 @@ import * as Bluebird from 'bluebird';
import * as fs from 'fs'; import * as fs from 'fs';
import * as _ from 'lodash'; import * as _ from 'lodash';
import log from './supervisor-console';
// FIXME: Don't use synchronous file reading and change call sites to support a promise // FIXME: Don't use synchronous file reading and change call sites to support a promise
function getOSReleaseField(path: string, field: string): string | undefined { function getOSReleaseField(path: string, field: string): string | undefined {
try { try {
@ -21,7 +23,7 @@ function getOSReleaseField(path: string, field: string): string | undefined {
// Remove enclosing quotes: http://stackoverflow.com/a/19156197/2549019 // Remove enclosing quotes: http://stackoverflow.com/a/19156197/2549019
return releaseItems[field].replace(/^"(.+(?="$))"$/, '$1'); return releaseItems[field].replace(/^"(.+(?="$))"$/, '$1');
} catch (err) { } catch (err) {
console.log('Could not get OS release field: ', err.message); log.error('Could not get OS release field: ', err);
return; return;
} }
} }

View File

@ -0,0 +1,90 @@
import * as _ from 'lodash';
import { TransformableInfo } from 'logform';
import * as winston from 'winston';
const levels = {
error: 0,
warn: 1,
success: 2,
event: 3,
api: 4,
info: 5,
debug: 6,
};
type logLevel = keyof typeof levels;
const colors: { [key in logLevel]: string | string[] } = {
error: 'red',
warn: 'yellow',
success: 'green',
event: 'cyan',
info: 'blue',
debug: 'magenta',
api: ['black', 'bgWhite'],
};
const maxLevelLength = _(levels)
.map((_v, k) => k.length)
.max();
const uncolorize = winston.format.uncolorize();
const formatter = winston.format.printf(args => {
const { level, message } = args;
const { level: strippedLevel } = uncolorize.transform(args, {
level: true,
message: true,
}) as TransformableInfo;
return `[${level}]${_.repeat(
' ',
maxLevelLength! - strippedLevel.length + 1,
)}${message}`;
});
export const winstonLog = (winston.createLogger({
format: winston.format.combine(winston.format.colorize(), formatter),
transports: [new winston.transports.Console()],
// In the future we can reduce this logging level in
// certain scenarios, but for now we don't want to ignore
// any debugging without a rock solid method of making
// sure that debug logs are shown. For example a switch on
// the dashboard, a supervisor api call and supervisor
// process crash detection
level: 'debug',
levels,
// A bit hacky to get all the correct types for the logger
// below, we first cast to unknown so we can do what we
// like, and then assign every log level a function (which
// is what happens internally in winston)
}) as unknown) as { [key in logLevel]: (message: string) => void };
winston.addColors(colors);
const messageFormatter = (printFn: (message: string) => void) => {
return (...parts: any[]) => {
parts
.map(p => {
if (p instanceof Error) {
return p.stack;
}
return p;
})
.join(' ')
.replace('\n', '\n ')
.split('\n')
.forEach(printFn);
};
};
export const log: { [key in logLevel]: (...messageParts: any[]) => void } = {
error: messageFormatter(winstonLog.error),
warn: messageFormatter(winstonLog.warn),
success: messageFormatter(winstonLog.success),
event: messageFormatter(winstonLog.event),
info: messageFormatter(winstonLog.info),
debug: messageFormatter(winstonLog.debug),
api: messageFormatter(winstonLog.api),
};
export default log;

View File

@ -3,6 +3,8 @@ import { inspect } from 'util';
import { EnvVarObject, LabelObject } from './types'; import { EnvVarObject, LabelObject } from './types';
import log from './supervisor-console';
export interface CheckIntOptions { export interface CheckIntOptions {
positive?: boolean; positive?: boolean;
} }
@ -100,29 +102,37 @@ export function isValidShortText(t: string): boolean {
*/ */
export function isValidEnv(obj: EnvVarObject): boolean { export function isValidEnv(obj: EnvVarObject): boolean {
if (!_.isObject(obj)) { if (!_.isObject(obj)) {
console.log('debug: Non-object passed to validation.isValidEnv'); log.debug(
console.log(`\tobj: ${inspect(obj)}`); `Non-object passed to validation.isValidEnv\nobj: ${inspect(obj)}`,
);
return false; return false;
} }
return _.every(obj, (val, key) => { return _.every(obj, (val, key) => {
if (!isValidShortText(key)) { if (!isValidShortText(key)) {
console.log( log.debug(
'debug: Non-valid short text env var key passed to validation.isValidEnv', `Non-valid short text env var key passed to validation.isValidEnv\nKey: ${inspect(
key,
)}`,
); );
console.log(`\tKey: ${inspect(key)}`);
return false; return false;
} }
if (!ENV_VAR_KEY_REGEX.test(key)) { if (!ENV_VAR_KEY_REGEX.test(key)) {
console.log('debug: Invalid env var key passed to validation.isValidEnv'); log.debug(
console.log(`\tKey: ${inspect(key)}`); `Invalid env var key passed to validation.isValidEnv\nKey: ${inspect(
key,
)}`,
);
return false; return false;
} }
if (!_.isString(val)) { if (!_.isString(val)) {
console.log('debug: Non-string value passed to validation.isValidEnv'); log.debug(
console.log(`\tval: ${inspect(key)}`); `Non-string value passed to validation.isValidEnv\nValue: ${inspect(
key,
)}`,
);
return false; return false;
} }
return true; return true;
@ -136,33 +146,39 @@ export function isValidEnv(obj: EnvVarObject): boolean {
*/ */
export function isValidLabelsObject(obj: LabelObject): boolean { export function isValidLabelsObject(obj: LabelObject): boolean {
if (!_.isObject(obj)) { if (!_.isObject(obj)) {
console.log('debug: Non-object passed to validation.isValidLabelsObject'); log.debug(
console.log(`\tobj: ${inspect(obj)}`); `Non-object passed to validation.isValidLabelsObject\nobj: ${inspect(
obj,
)}`,
);
return false; return false;
} }
return _.every(obj, (val, key) => { return _.every(obj, (val, key) => {
if (!isValidShortText(key)) { if (!isValidShortText(key)) {
console.log( log.debug(
'debug: Non-valid short text label key passed to validation.isValidLabelsObject', `Non-valid short text label key passed to validation.isValidLabelsObject\nKey: ${inspect(
key,
)}`,
); );
console.log(`\tkey: ${inspect(key)}`);
return false; return false;
} }
if (!LABEL_NAME_REGEX.test(key)) { if (!LABEL_NAME_REGEX.test(key)) {
console.log( log.debug(
'debug: Invalid label name passed to validation.isValidLabelsObject', `Invalid label name passed to validation.isValidLabelsObject\nKey: ${inspect(
key,
)}`,
); );
console.log(`\tkey: ${inspect(key)}`);
return false; return false;
} }
if (!_.isString(val)) { if (!_.isString(val)) {
console.log( log.debug(
'debug: Non-string value passed to validation.isValidLabelsObject', `Non-string value passed to validation.isValidLabelsObject\nValue: ${inspect(
val,
)}`,
); );
console.log(`\tval: ${inspect(val)}`);
return false; return false;
} }
@ -174,8 +190,8 @@ export function isValidDeviceName(name: string): boolean {
// currently the only disallowed value in a device name is a newline // currently the only disallowed value in a device name is a newline
const newline = name.indexOf('\n') !== -1; const newline = name.indexOf('\n') !== -1;
if (newline) { if (newline) {
console.log( log.debug(
'debug: newline found in device name. This is invalid and should be removed', 'Newline found in device name. This is invalid and should be removed',
); );
} }
return !newline; return !newline;
@ -194,10 +210,10 @@ function undefinedOrValidEnv(val: EnvVarObject): boolean {
*/ */
export function isValidDependentAppsObject(apps: any): boolean { export function isValidDependentAppsObject(apps: any): boolean {
if (!_.isObject(apps)) { if (!_.isObject(apps)) {
console.log( log.debug(
'debug: non-object passed to validation.isValidDependentAppsObject', 'Non-object passed to validation.isValidDependentAppsObject\nApps:',
inspect(apps),
); );
console.log(`\tapps: ${inspect(apps)}`);
return false; return false;
} }
@ -210,60 +226,60 @@ export function isValidDependentAppsObject(apps: any): boolean {
}); });
if (!isValidShortText(appId) || !checkInt(appId)) { if (!isValidShortText(appId) || !checkInt(appId)) {
console.log( log.debug(
'debug: Invalid appId passed to validation.isValidDependentAppsObject', 'Invalid appId passed to validation.isValidDependentAppsObject\nappId:',
inspect(appId),
); );
console.log(`\tappId: ${inspect(appId)}`);
return false; return false;
} }
return _.conformsTo(val, { return _.conformsTo(val, {
name: (n: any) => { name: (n: any) => {
if (!isValidShortText(n)) { if (!isValidShortText(n)) {
console.log( log.debug(
'debug: Invalid name passed to validation.isValidDependentAppsObject', 'Invalid name passed to validation.isValidDependentAppsObject\nName:',
inspect(n),
); );
console.log(`\tname: ${inspect(n)}`);
return false; return false;
} }
return true; return true;
}, },
image: (i: any) => { image: (i: any) => {
if (val.commit != null && !isValidShortText(i)) { if (val.commit != null && !isValidShortText(i)) {
console.log( log.debug(
'debug: non valid image passed to validation.isValidDependentAppsObject', 'Non valid image passed to validation.isValidDependentAppsObject\nImage:',
inspect(i),
); );
console.log(`\timage: ${inspect(i)}`);
return false; return false;
} }
return true; return true;
}, },
commit: (c: any) => { commit: (c: any) => {
if (c != null && !isValidShortText(c)) { if (c != null && !isValidShortText(c)) {
console.log( log.debug(
'debug: invalid commit passed to validation.isValidDependentAppsObject', 'invalid commit passed to validation.isValidDependentAppsObject\nCommit:',
inspect(c),
); );
console.log(`\tcommit: ${inspect(c)}`);
return false; return false;
} }
return true; return true;
}, },
config: (c: any) => { config: (c: any) => {
if (!undefinedOrValidEnv(c)) { if (!undefinedOrValidEnv(c)) {
console.log( log.debug(
'debug; Invalid config passed to validation.isValidDependentAppsObject', 'Invalid config passed to validation.isValidDependentAppsObject\nConfig:',
inspect(c),
); );
console.log(`\tconfig: ${inspect(c)}`);
return false; return false;
} }
return true; return true;
}, },
environment: (e: any) => { environment: (e: any) => {
if (!undefinedOrValidEnv(e)) { if (!undefinedOrValidEnv(e)) {
console.log( log.debug(
'debug; Invalid environment passed to validation.isValidDependentAppsObject', 'Invalid environment passed to validation.isValidDependentAppsObject\nEnvironment:',
inspect(e),
); );
console.log(`\tenvironment: ${inspect(e)}`);
return false; return false;
} }
return true; return true;
@ -274,56 +290,60 @@ export function isValidDependentAppsObject(apps: any): boolean {
function isValidService(service: any, serviceId: string): boolean { function isValidService(service: any, serviceId: string): boolean {
if (!isValidShortText(serviceId) || !checkInt(serviceId)) { if (!isValidShortText(serviceId) || !checkInt(serviceId)) {
console.log( log.debug(
'debug: Invalid service id passed to validation.isValidService', 'Invalid service id passed to validation.isValidService\nService ID:',
inspect(serviceId),
); );
console.log(`\tserviceId: ${inspect(serviceId)}`);
return false; return false;
} }
return _.conformsTo(service, { return _.conformsTo(service, {
serviceName: (n: any) => { serviceName: (n: any) => {
if (!isValidShortText(n)) { if (!isValidShortText(n)) {
console.log( log.debug(
'debug: Invalid service name passed to validation.isValidService', 'Invalid service name passed to validation.isValidService\nService Name:',
inspect(n),
); );
console.log(`\tserviceName: ${inspect(n)}`);
return false; return false;
} }
return true; return true;
}, },
image: (i: any) => { image: (i: any) => {
if (!isValidShortText(i)) { if (!isValidShortText(i)) {
console.log('debug: Invalid image passed to validation.isValidService'); log.debug(
console.log(`\timage: ${inspect(i)}`); 'Invalid image passed to validation.isValidService\nImage:',
inspect(i),
);
return false; return false;
} }
return true; return true;
}, },
environment: (e: any) => { environment: (e: any) => {
if (!isValidEnv(e)) { if (!isValidEnv(e)) {
console.log('debug: Invalid env passed to validation.isValidService'); log.debug(
console.log(`\tenvironment: ${inspect(e)}`); 'Invalid env passed to validation.isValidService\nEnvironment:',
inspect(e),
);
return false; return false;
} }
return true; return true;
}, },
imageId: (i: any) => { imageId: (i: any) => {
if (checkInt(i) == null) { if (checkInt(i) == null) {
console.log( log.debug(
'debug: Invalid image id passed to validation.isValidService', 'Invalid image id passed to validation.isValidService\nImage ID:',
inspect(i),
); );
console.log(`\timageId: ${inspect(i)}`);
return false; return false;
} }
return true; return true;
}, },
labels: (l: any) => { labels: (l: any) => {
if (!isValidLabelsObject(l)) { if (!isValidLabelsObject(l)) {
console.log( log.debug(
'debug: Invalid labels object passed to validation.isValidService', 'Invalid labels object passed to validation.isValidService\nLabels:',
inspect(l),
); );
console.log(`\tlabels: ${inspect(l)}`);
return false; return false;
} }
return true; return true;
@ -341,56 +361,58 @@ function isValidService(service: any, serviceId: string): boolean {
*/ */
export function isValidAppsObject(obj: any): boolean { export function isValidAppsObject(obj: any): boolean {
if (!_.isObject(obj)) { if (!_.isObject(obj)) {
console.log('debug: Invalid object passed to validation.isValidAppsObject'); log.debug(
console.log(`\tobj: ${inspect(obj)}`); 'Invalid object passed to validation.isValidAppsObject\nobj:',
inspect(obj),
);
return false; return false;
} }
return _.every(obj, (val, appId) => { return _.every(obj, (val, appId) => {
if (!isValidShortText(appId) || !checkInt(appId)) { if (!isValidShortText(appId) || !checkInt(appId)) {
console.log( log.debug(
'debug: Invalid appId passed to validation.isValidAppsObject', 'Invalid appId passed to validation.isValidAppsObject\nApp ID:',
inspect(appId),
); );
console.log(`\tappId: ${inspect(appId)}`);
return false; return false;
} }
return _.conformsTo(_.defaults(_.clone(val), { releaseId: undefined }), { return _.conformsTo(_.defaults(_.clone(val), { releaseId: undefined }), {
name: (n: any) => { name: (n: any) => {
if (!isValidShortText(n)) { if (!isValidShortText(n)) {
console.log( log.debug(
'debug: Invalid service name passed to validation.isValidAppsObject', 'Invalid service name passed to validation.isValidAppsObject\nName:',
inspect(n),
); );
console.log(`\tname: ${inspect(n)}`);
return false; return false;
} }
return true; return true;
}, },
releaseId: (r: any) => { releaseId: (r: any) => {
if (r != null && checkInt(r) == null) { if (r != null && checkInt(r) == null) {
console.log( log.debug(
'debug: Invalid releaseId passed to validation.isValidAppsObject', 'Invalid releaseId passed to validation.isValidAppsObject\nRelease ID',
inspect(r),
); );
console.log(`\treleaseId: ${inspect(r)}`);
return false; return false;
} }
return true; return true;
}, },
services: (s: any) => { services: (s: any) => {
if (!_.isObject(s)) { if (!_.isObject(s)) {
console.log( log.debug(
'debug: Non-object service passed to validation.isValidAppsObject', 'Non-object service passed to validation.isValidAppsObject\nServices:',
inspect(s),
); );
console.log(`\tservices: ${inspect(s)}`);
return false; return false;
} }
return _.every(s, (svc, svcId) => { return _.every(s, (svc, svcId) => {
if (!isValidService(svc, svcId)) { if (!isValidService(svc, svcId)) {
console.log( log.debug(
'debug: Invalid service object passed to validation.isValidAppsObject', 'Invalid service object passed to validation.isValidAppsObject\nService:',
inspect(svc),
); );
console.log(`\tsvc: ${inspect(svc)}`);
return false; return false;
} }
return true; return true;
@ -407,45 +429,45 @@ export function isValidAppsObject(obj: any): boolean {
*/ */
export function isValidDependentDevicesObject(devices: any): boolean { export function isValidDependentDevicesObject(devices: any): boolean {
if (!_.isObject(devices)) { if (!_.isObject(devices)) {
console.log( log.debug(
'debug: Non-object passed to validation.isValidDependentDevicesObject', 'Non-object passed to validation.isValidDependentDevicesObject\nDevices:',
inspect(devices),
); );
console.log(`\tdevices: ${inspect(devices)}`);
return false; return false;
} }
return _.every(devices, (val, uuid) => { return _.every(devices, (val, uuid) => {
if (!isValidShortText(uuid)) { if (!isValidShortText(uuid)) {
console.log( log.debug(
'debug: Invalid uuid passed to validation.isValidDependentDevicesObject', 'Invalid uuid passed to validation.isValidDependentDevicesObject\nuuid:',
inspect(uuid),
); );
console.log(`\tuuid: ${inspect(uuid)}`);
return false; return false;
} }
return _.conformsTo(val, { return _.conformsTo(val, {
name: (n: any) => { name: (n: any) => {
if (!isValidShortText(n)) { if (!isValidShortText(n)) {
console.log( log.debug(
'debug: Invalid device name passed to validation.isValidDependentDevicesObject', 'Invalid device name passed to validation.isValidDependentDevicesObject\nName:',
inspect(n),
); );
console.log(`\tname: ${inspect(n)}`);
return false; return false;
} }
return true; return true;
}, },
apps: (a: any) => { apps: (a: any) => {
if (!_.isObject(a)) { if (!_.isObject(a)) {
console.log( log.debug(
'debug: Invalid apps object passed to validation.isValidDependentDevicesObject', 'Invalid apps object passed to validation.isValidDependentDevicesObject\nApps:',
inspect(a),
); );
console.log(`\tapps: ${inspect(a)}`);
return false; return false;
} }
if (_.isEmpty(a)) { if (_.isEmpty(a)) {
console.log( log.debug(
'debug: Empty object passed to validation.isValidDependentDevicesObject', 'Empty object passed to validation.isValidDependentDevicesObject',
); );
return false; return false;
} }
@ -458,20 +480,20 @@ export function isValidDependentDevicesObject(devices: any): boolean {
return _.conformsTo(app, { return _.conformsTo(app, {
config: (c: any) => { config: (c: any) => {
if (!undefinedOrValidEnv(c)) { if (!undefinedOrValidEnv(c)) {
console.log( log.debug(
'debug: Invalid config passed to validation.isValidDependentDevicesObject', 'Invalid config passed to validation.isValidDependentDevicesObject\nConfig:',
inspect(c),
); );
console.log(`\tconfig: ${inspect(c)}`);
return false; return false;
} }
return true; return true;
}, },
environment: (e: any) => { environment: (e: any) => {
if (!undefinedOrValidEnv(e)) { if (!undefinedOrValidEnv(e)) {
console.log( log.debug(
'debug: Invalid environment passed to validation.isValidDependentDevicesObject', 'Invalid environment passed to validation.isValidDependentDevicesObject\nConfig:',
inspect(e),
); );
console.log(`\tconfig: ${inspect(e)}`);
return false; return false;
} }
return true; return true;

View File

@ -6,6 +6,8 @@ import Config from './config';
import Database from './db'; import Database from './db';
import { Logger } from './logger'; import { Logger } from './logger';
import log from './lib/supervisor-console';
/** /**
* This class handles any special cases necessary for switching * This class handles any special cases necessary for switching
* modes in localMode. * modes in localMode.
@ -43,7 +45,7 @@ export class LocalModeManager {
// as local mode needs to be set // as local mode needs to be set
let unmanagedLocalMode = false; let unmanagedLocalMode = false;
if (await this.config.get('unmanaged')) { if (await this.config.get('unmanaged')) {
console.log('Starting up in unmanaged mode, activating local mode'); log.info('Starting up in unmanaged mode, activating local mode');
await this.config.set({ localMode: true }); await this.config.set({ localMode: true });
unmanagedLocalMode = true; unmanagedLocalMode = true;
} }
@ -64,11 +66,11 @@ export class LocalModeManager {
const containers = await this.getLocalModeContainers(images); const containers = await this.getLocalModeContainers(images);
await Bluebird.map(containers, containerId => { await Bluebird.map(containers, containerId => {
console.log('Removing local mode container: ', containerId); log.debug('Removing local mode container: ', containerId);
return this.docker.getContainer(containerId).remove({ force: true }); return this.docker.getContainer(containerId).remove({ force: true });
}); });
await Bluebird.map(images, imageId => { await Bluebird.map(images, imageId => {
console.log('Removing local mode image: ', imageId); log.debug('Removing local mode image: ', imageId);
return this.docker.getImage(imageId).remove({ force: true }); return this.docker.getImage(imageId).remove({ force: true });
}); });
@ -78,7 +80,7 @@ export class LocalModeManager {
.del() .del()
.where({ source: 'local' }); .where({ source: 'local' });
} catch (e) { } catch (e) {
console.log('There was an error clearing local mode artifacts: ', e); log.error('There was an error clearing local mode artifacts: ', e);
} }
} }

View File

@ -15,6 +15,8 @@ import {
} from './logging'; } from './logging';
import LogMonitor from './logging/monitor'; import LogMonitor from './logging/monitor';
import log from './lib/supervisor-console';
interface LoggerSetupOptions { interface LoggerSetupOptions {
apiEndpoint: string; apiEndpoint: string;
uuid: string; uuid: string;
@ -69,11 +71,11 @@ export class Logger {
if (localMode) { if (localMode) {
// Use the local mode backend // Use the local mode backend
this.backend = this.localBackend; this.backend = this.localBackend;
console.log('Switching logging backend to LocalLogBackend'); log.info('Switching logging backend to LocalLogBackend');
} else { } else {
// Use the balena backend // Use the balena backend
this.backend = this.balenaBackend; this.backend = this.balenaBackend;
console.log('Switching logging backend to BalenaLogBackend'); log.info('Switching logging backend to BalenaLogBackend');
} }
} }
@ -146,7 +148,7 @@ export class Logger {
const logs = new ContainerLogs(containerId, docker); const logs = new ContainerLogs(containerId, docker);
this.containerLogs[containerId] = logs; this.containerLogs[containerId] = logs;
logs.on('error', err => { logs.on('error', err => {
console.error(`Container log retrieval error: ${err}`); log.error('Container log retrieval error', err);
delete this.containerLogs[containerId]; delete this.containerLogs[containerId];
}); });
logs.on('log', async logMessage => { logs.on('log', async logMessage => {
@ -184,7 +186,7 @@ export class Logger {
if (_.isEmpty(errorMessage)) { if (_.isEmpty(errorMessage)) {
errorMessage = errorMessage =
obj.error.name !== 'Error' ? obj.error.name : 'Unknown cause'; obj.error.name !== 'Error' ? obj.error.name : 'Unknown cause';
console.error('Warning: invalid error message', obj.error); log.warn('Invalid error message', obj.error);
} }
message += ` due to '${errorMessage}'`; message += ` due to '${errorMessage}'`;
} }
@ -214,7 +216,7 @@ export class Logger {
} }
public async clearOutOfDateDBLogs(containerIds: string[]) { public async clearOutOfDateDBLogs(containerIds: string[]) {
console.log('Performing database cleanup for container log timestamps'); log.debug('Performing database cleanup for container log timestamps');
await this.db await this.db
.models('containerLogs') .models('containerLogs')
.whereNotIn('containerId', containerIds) .whereNotIn('containerId', containerIds)

View File

@ -7,6 +7,8 @@ import * as zlib from 'zlib';
import { LogBackend, LogMessage } from './log-backend'; import { LogBackend, LogMessage } from './log-backend';
import log from '../lib/supervisor-console';
const ZLIB_TIMEOUT = 100; const ZLIB_TIMEOUT = 100;
const COOLDOWN_PERIOD = 5 * 1000; const COOLDOWN_PERIOD = 5 * 1000;
const KEEPALIVE_TIMEOUT = 60 * 1000; const KEEPALIVE_TIMEOUT = 60 * 1000;
@ -105,7 +107,7 @@ export class BalenaLogBackend extends LogBackend {
// only reason for the server to prematurely respond is to // only reason for the server to prematurely respond is to
// communicate an error. So teardown the connection immediately // communicate an error. So teardown the connection immediately
this.req.on('response', res => { this.req.on('response', res => {
console.log( log.error(
'LogBackend: server responded with status code:', 'LogBackend: server responded with status code:',
res.statusCode, res.statusCode,
); );
@ -115,7 +117,7 @@ export class BalenaLogBackend extends LogBackend {
this.req.on('timeout', () => this.teardown()); this.req.on('timeout', () => this.teardown());
this.req.on('close', () => this.teardown()); this.req.on('close', () => this.teardown());
this.req.on('error', err => { this.req.on('error', err => {
console.log('LogBackend: unexpected error:', err); log.error('LogBackend: unexpected error:', err);
this.teardown(); this.teardown();
}); });

View File

@ -5,6 +5,8 @@ import { Readable } from 'stream';
import { checkInt } from '../lib/validation'; import { checkInt } from '../lib/validation';
import { LogBackend, LogMessage } from './log-backend'; import { LogBackend, LogMessage } from './log-backend';
import log from '../lib/supervisor-console';
export class LocalLogBackend extends LogBackend { export class LocalLogBackend extends LogBackend {
private globalListeners: Readable[] = []; private globalListeners: Readable[] = [];
@ -21,10 +23,10 @@ export class LocalLogBackend extends LogBackend {
} }
const svcId = checkInt(message.serviceId); const svcId = checkInt(message.serviceId);
if (svcId == null) { if (svcId == null) {
console.log( log.warn(
'Warning: Non-integer service id found in local logs: ', 'Non-integer service id found in local logs:\n',
JSON.stringify(message),
); );
console.log(` ${JSON.stringify(message)}`);
return null; return null;
} }
// TODO: Can we cache this value? The service ids are reused, so // TODO: Can we cache this value? The service ids are reused, so
@ -44,7 +46,7 @@ export class LocalLogBackend extends LogBackend {
} }
}) })
.catch(e => { .catch(e => {
console.log('Error streaming local log output: ', e); log.error('Error streaming local log output:', e);
}); });
} }
} }

View File

@ -1,5 +1,7 @@
import Database from '../db'; import Database from '../db';
import log from '../lib/supervisor-console';
// Flush every 10 mins // Flush every 10 mins
const DB_FLUSH_INTERVAL = 10 * 60 * 1000; const DB_FLUSH_INTERVAL = 10 * 60 * 1000;
@ -46,8 +48,9 @@ export class LogMonitor {
this.timestamps[containerId] = timestampObj.lastSentTimestamp; this.timestamps[containerId] = timestampObj.lastSentTimestamp;
} }
} catch (e) { } catch (e) {
console.error( log.error(
`There was an error retrieving the container log timestamps: ${e}`, 'There was an error retrieving the container log timestamps:',
e,
); );
} }
} }
@ -55,7 +58,7 @@ export class LogMonitor {
} }
private async flushDb() { private async flushDb() {
console.log('Attempting container log timestamp flush...'); log.debug('Attempting container log timestamp flush...');
const containerIds = Object.getOwnPropertyNames(this.timestamps); const containerIds = Object.getOwnPropertyNames(this.timestamps);
try { try {
for (const containerId of containerIds) { for (const containerId of containerIds) {
@ -71,11 +74,9 @@ export class LogMonitor {
this.writeRequired[containerId] = false; this.writeRequired[containerId] = false;
} }
} catch (e) { } catch (e) {
console.error( log.error('There was an error storing the container log timestamps:', e);
`There was an error storing the container log timestamps: ${e}`,
);
} }
console.log('Container log timestamp flush complete'); log.debug('Container log timestamp flush complete');
} }
} }

View File

@ -11,6 +11,8 @@ import { checkTruthy } from './lib/validation';
import blink = require('./lib/blink'); import blink = require('./lib/blink');
import log from './lib/supervisor-console';
const networkPattern = { const networkPattern = {
blinks: 4, blinks: 4,
pause: 1000, pause: 1000,
@ -57,13 +59,13 @@ export const startConnectivityCheck = _.once(
) => { ) => {
enableConnectivityCheck(enable); enableConnectivityCheck(enable);
if (!apiEndpoint) { if (!apiEndpoint) {
console.log('No API endpoint specified, skipping connectivity check'); log.debug('No API endpoint specified, skipping connectivity check');
return; return;
} }
await Bluebird.resolve(fs.mkdir(constants.vpnStatusPath)) await Bluebird.resolve(fs.mkdir(constants.vpnStatusPath))
.catch(EEXIST, () => { .catch(EEXIST, () => {
console.log('VPN status path exists.'); log.debug('VPN status path exists.');
}) })
.then(() => { .then(() => {
fs.watch(constants.vpnStatusPath, vpnStatusInotifyCallback); fs.watch(constants.vpnStatusPath, vpnStatusInotifyCallback);
@ -88,10 +90,10 @@ export const startConnectivityCheck = _.once(
onChangeCallback(connected); onChangeCallback(connected);
} }
if (connected) { if (connected) {
console.log('Internet Connectivity: OK'); log.info('Internet Connectivity: OK');
blink.pattern.stop(); blink.pattern.stop();
} else { } else {
console.log('Waiting for connectivity...'); log.info('Waiting for connectivity...');
blink.pattern.start(networkPattern); blink.pattern.start(networkPattern);
} }
}, },
@ -103,7 +105,7 @@ export function enableConnectivityCheck(enable: boolean) {
const boolEnable = checkTruthy(enable); const boolEnable = checkTruthy(enable);
enable = boolEnable != null ? boolEnable : true; enable = boolEnable != null ? boolEnable : true;
enableCheck(enable); enableCheck(enable);
console.log(`Connectivity check enabled: ${enable}`); log.debug(`Connectivity check enabled: ${enable}`);
} }
export const connectivityCheckEnabled = Bluebird.method( export const connectivityCheckEnabled = Bluebird.method(

View File

@ -11,6 +11,8 @@ bodyParser = require 'body-parser'
execAsync = Promise.promisify(require('child_process').exec) execAsync = Promise.promisify(require('child_process').exec)
url = require 'url' url = require 'url'
{ log } = require './lib/supervisor-console'
isDefined = _.negate(_.isUndefined) isDefined = _.negate(_.isUndefined)
parseDeviceFields = (device) -> parseDeviceFields = (device) ->
@ -110,7 +112,7 @@ createProxyvisorRouter = (proxyvisor) ->
.then -> .then ->
res.status(201).send(dev) res.status(201).send(dev)
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
router.get '/v1/devices/:uuid', (req, res) -> router.get '/v1/devices/:uuid', (req, res) ->
@ -121,7 +123,7 @@ createProxyvisorRouter = (proxyvisor) ->
return res.status(410).send('Device deleted') if device.markedForDeletion return res.status(410).send('Device deleted') if device.markedForDeletion
res.json(parseDeviceFields(device)) res.json(parseDeviceFields(device))
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
router.post '/v1/devices/:uuid/logs', (req, res) -> router.post '/v1/devices/:uuid/logs', (req, res) ->
@ -139,7 +141,7 @@ createProxyvisorRouter = (proxyvisor) ->
proxyvisor.logger.logDependent(m, uuid) proxyvisor.logger.logDependent(m, uuid)
res.status(202).send('OK') res.status(202).send('OK')
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
router.put '/v1/devices/:uuid', (req, res) -> router.put '/v1/devices/:uuid', (req, res) ->
@ -192,7 +194,7 @@ createProxyvisorRouter = (proxyvisor) ->
.then ([ device ]) -> .then ([ device ]) ->
res.json(parseDeviceFields(device)) res.json(parseDeviceFields(device))
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
router.get '/v1/dependent-apps/:appId/assets/:commit', (req, res) -> router.get '/v1/dependent-apps/:appId/assets/:commit', (req, res) ->
@ -207,7 +209,7 @@ createProxyvisorRouter = (proxyvisor) ->
.then -> .then ->
res.sendFile(dest) res.sendFile(dest)
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
router.get '/v1/dependent-apps', (req, res) -> router.get '/v1/dependent-apps', (req, res) ->
@ -222,7 +224,7 @@ createProxyvisorRouter = (proxyvisor) ->
.then (apps) -> .then (apps) ->
res.json(apps) res.json(apps)
.catch (err) -> .catch (err) ->
console.error("Error on #{req.method} #{url.parse(req.url).pathname}", err, err.stack) log.error("Error on #{req.method} #{url.parse(req.url).pathname}", err)
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
return router return router
@ -605,7 +607,7 @@ module.exports = class Proxyvisor
@acknowledgedState[device.uuid] = null @acknowledgedState[device.uuid] = null
throw new Error("Hook returned #{response.statusCode}: #{body}") if response.statusCode != 202 throw new Error("Hook returned #{response.statusCode}: #{body}") if response.statusCode != 202
.catch (err) -> .catch (err) ->
return console.error("Error updating device #{device.uuid}", err, err.stack) return log.error("Error updating device #{device.uuid}", err)
sendDeleteHook: ({ uuid }, timeout, endpoint) => sendDeleteHook: ({ uuid }, timeout, endpoint) =>
request.delAsync("#{endpoint}#{uuid}") request.delAsync("#{endpoint}#{uuid}")
@ -616,7 +618,7 @@ module.exports = class Proxyvisor
else else
throw new Error("Hook returned #{response.statusCode}: #{body}") throw new Error("Hook returned #{response.statusCode}: #{body}")
.catch (err) -> .catch (err) ->
return console.error("Error deleting device #{uuid}", err, err.stack) return log.error("Error deleting device #{uuid}", err)
sendUpdates: ({ uuid }) => sendUpdates: ({ uuid }) =>
Promise.join( Promise.join(
@ -624,7 +626,7 @@ module.exports = class Proxyvisor
@config.get('apiTimeout') @config.get('apiTimeout')
([ dev ], apiTimeout) => ([ dev ], apiTimeout) =>
if !dev? if !dev?
console.log("Warning, trying to send update to non-existent device #{uuid}") log.warn("Trying to send update to non-existent device #{uuid}")
return return
@normaliseDependentDeviceFromDB(dev) @normaliseDependentDeviceFromDB(dev)
.then (device) => .then (device) =>

View File

@ -9,6 +9,8 @@ import blink = require('./lib/blink');
import * as iptables from './lib/iptables'; import * as iptables from './lib/iptables';
import { checkTruthy } from './lib/validation'; import { checkTruthy } from './lib/validation';
import log from './lib/supervisor-console';
function getKeyFromReq(req: express.Request): string | null { function getKeyFromReq(req: express.Request): string | null {
const queryKey = req.query.apikey; const queryKey = req.query.apikey;
if (queryKey != null) { if (queryKey != null) {
@ -54,9 +56,9 @@ function authenticate(config: Config): express.RequestHandler {
}; };
} }
const expressLogger = morgan((tokens, req, res) => const expressLogger = morgan(
(tokens, req, res) =>
[ [
'Supervisor API:',
tokens.method(req, res), tokens.method(req, res),
req.path, req.path,
tokens.status(req, res), tokens.status(req, res),
@ -64,6 +66,9 @@ const expressLogger = morgan((tokens, req, res) =>
tokens['response-time'](req, res), tokens['response-time'](req, res),
'ms', 'ms',
].join(' '), ].join(' '),
{
stream: { write: d => log.api(d.toString().trimRight()) },
},
); );
interface SupervisorAPIConstructOpts { interface SupervisorAPIConstructOpts {
@ -169,16 +174,16 @@ export class SupervisorAPI {
try { try {
if (checkTruthy(allInterfaces)) { if (checkTruthy(allInterfaces)) {
await iptables.removeRejections(port); await iptables.removeRejections(port);
console.log('Supervisor API listening on all interfaces'); log.debug('Supervisor API listening on all interfaces');
} else { } else {
await iptables.rejectOnAllInterfacesExcept(allowedInterfaces, port); await iptables.rejectOnAllInterfacesExcept(allowedInterfaces, port);
console.log('Supervisor API listening on allowed interfaces only'); log.debug('Supervisor API listening on allowed interfaces only');
} }
} catch (err) { } catch (err) {
console.log( log.error(
'Error on switching supervisor API listening rules - stopping API.', 'Error on switching supervisor API listening rules - stopping API.\n',
err,
); );
console.log(' ', err);
this.stop(); this.stop();
} }
} }

View File

@ -10,6 +10,9 @@ DeviceState = require './device-state'
{ SupervisorAPI } = require './supervisor-api' { SupervisorAPI } = require './supervisor-api'
{ Logger } = require './logger' { Logger } = require './logger'
version = require './lib/supervisor-version'
{ log } = require './lib/supervisor-console'
constants = require './lib/constants' constants = require './lib/constants'
startupConfigFields = [ startupConfigFields = [
@ -56,6 +59,9 @@ module.exports = class Supervisor extends EventEmitter
}) })
init: => init: =>
log.info("Supervisor v#{version} starting up...")
@db.init() @db.init()
.tap => .tap =>
@config.init() # Ensures uuid, deviceApiKey, apiSecret @config.init() # Ensures uuid, deviceApiKey, apiSecret
@ -65,13 +71,13 @@ module.exports = class Supervisor extends EventEmitter
# We can't print to the dashboard until the logger has started up, # We can't print to the dashboard until the logger has started up,
# so we leave a trail of breadcrumbs in the logs in case runtime # so we leave a trail of breadcrumbs in the logs in case runtime
# fails to get to the first dashboard logs # fails to get to the first dashboard logs
console.log('Starting event tracker') log.debug('Starting event tracker')
@eventTracker.init(_.assign({}, conf, { @config })) @eventTracker.init(_.assign({}, conf, { @config }))
.then => .then =>
console.log('Starting up api binder') log.debug('Starting up api binder')
@apiBinder.initClient() @apiBinder.initClient()
.then => .then =>
console.log('Starting logging infrastructure') log.debug('Starting logging infrastructure')
@logger.init({ @logger.init({
apiEndpoint: conf.apiEndpoint, apiEndpoint: conf.apiEndpoint,
uuid: conf.uuid, uuid: conf.uuid,
@ -84,13 +90,13 @@ module.exports = class Supervisor extends EventEmitter
@logger.logSystemMessage('Supervisor starting', {}, 'Supervisor start') @logger.logSystemMessage('Supervisor starting', {}, 'Supervisor start')
.then => .then =>
if conf.legacyAppsPresent if conf.legacyAppsPresent
console.log('Legacy app detected, running migration') log.info('Legacy app detected, running migration')
@deviceState.normaliseLegacy(@apiBinder.balenaApi) @deviceState.normaliseLegacy(@apiBinder.balenaApi)
.then => .then =>
@deviceState.init() @deviceState.init()
.then => .then =>
# initialize API # initialize API
console.log('Starting API server') log.info('Starting API server')
@api.listen(constants.allowedInterfaces, conf.listenPort, conf.apiTimeout) @api.listen(constants.allowedInterfaces, conf.listenPort, conf.apiTimeout)
@deviceState.on('shutdown', => @api.stop()) @deviceState.on('shutdown', => @api.stop())
.then => .then =>

View File

@ -20,6 +20,20 @@ const dockerode = require('dockerode');
const chokidar = require('chokidar'); const chokidar = require('chokidar');
const _ = require('lodash'); const _ = require('lodash');
require('ts-node/register');
const { ContainerLogs } = require('./src/logging/container');
const setupLogs = (containerId, docker) => {
console.log('Setting up logs');
const logs = new ContainerLogs(containerId, docker);
logs.on('log', ({ message }) => {
if (message.trim().length !== 0) {
console.log(message);
}
});
logs.attach(Date.now());
};
const docker = new dockerode({ const docker = new dockerode({
host: ip, host: ip,
port: 2375, port: 2375,
@ -53,10 +67,11 @@ function extractMessage(msgBuf) {
let changedFiles = []; let changedFiles = [];
let deletedFiles = []; let deletedFiles = [];
const performLivepush = _.debounce(async livepush => { const performLivepush = _.debounce(async (livepush, containerId, docker) => {
await livepush.performLivepush(changedFiles, deletedFiles); await livepush.performLivepush(changedFiles, deletedFiles);
changedFiles = []; changedFiles = [];
deletedFiles = []; deletedFiles = [];
setupLogs(containerId, docker);
}, 1000); }, 1000);
(async () => { (async () => {
@ -85,15 +100,15 @@ const performLivepush = _.debounce(async livepush => {
}) })
.on('add', path => { .on('add', path => {
changedFiles.push(path); changedFiles.push(path);
performLivepush(livepush); performLivepush(livepush, containerId, docker);
}) })
.on('change', path => { .on('change', path => {
changedFiles.push(path); changedFiles.push(path);
performLivepush(livepush); performLivepush(livepush, containerId, docker);
}) })
.on('unlink', path => { .on('unlink', path => {
deletedFiles.push(path); deletedFiles.push(path);
performLivepush(livepush); performLivepush(livepush, containerId, docker);
}); });
livepush.on('commandExecute', ({ command }) => { livepush.on('commandExecute', ({ command }) => {