-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Application Insights support to base images #18
base: master
Are you sure you want to change the base?
Conversation
@@ -18,15 +18,45 @@ if (typeof process.env.WEBSITE_ROLE_INSTANCE_ID !== 'undefined' | |||
roleInstanceId = process.env.WEBSITE_ROLE_INSTANCE_ID; | |||
} | |||
|
|||
var startupCommand = fs.readFileSync(CMDFILE, 'utf8').trim(); | |||
// Is Application Insights enabled, with an associated ikey? | |||
var appInsightsEnabled = process.env.ENABLE_APPINSIGHTS && process.env.APPINSIGHTS_INSTRUMENTATIONKEY; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per our previous discussion, the expectation is that if the ENABLE_APPINSIGHTS
is set, then an Application Insights resource has been provisioned, and its associated instrumentation key has been specified via the APPINSIGHTS_INSTRUMENTATIONKEY
variable (which the Application Insights SDK auto-detects).
|
||
// The command is using an unknown executable, and therefore, | ||
// the App Insights runtime can't be automatically enabled. | ||
return command; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is primarily meant to support the NPM start script scenario, where the app could specific an arbitrary command, that I'm not aware of a deterministic way to bootstrap Application Insights into. In practice, accommodating PM2 and Node should cover most scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fine for now.
8.1/startup/initAppInsights.js
Outdated
// Initialize the Application Insights runtime, using the | ||
// instrumentation key provided by the environment. | ||
require("applicationinsights").setup().start(); | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I check for the presence of the ikey before loading this script, there aren't are known reasons why this would fail. However, I added this error swallowing logic, since I assume we want to be sure this feature add-on doesn't impact the stability of the app itself.
8.1/startup/package.json
Outdated
@@ -4,6 +4,7 @@ | |||
"description": "Express-driven static site hosted from default App Service wwwroot directory", | |||
"main": "default-static-site.js", | |||
"dependencies": { | |||
"applicationinsights": "0.21.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to add the AI SDK dependency here, since the Dockerfile was already running npm install
in this directory, and it actually seemed logical to couple any "in-box" dependencies with the startup
directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, while I used a static version for this dependency, I'm cool with making it pick up patch changes if we thought that made sense. Since these images would need to be rebuilt to pull in any updated dependencies anyways, I figured it made sense to just be explicit about the version being bundled. Would love feedback though.
@@ -47,7 +77,7 @@ if (!startupCommand) { | |||
if (!startupCommand) { | |||
console.log("No startup command or autodetected startup script " + | |||
"found. Running default static site."); | |||
startupCommand = "node " + DEFAULTAPP; | |||
startupCommand = nodeCommandPrefix + DEFAULTAPP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could potentially skip initializing the AI runtime here, since it's just a "getting started" app. But, if the user enabled AI, they might expect to be able to see the HTTP traffic for the starter, in order to get a feel for the experience, before they push their own app code. Feedback would be appreciated here.
return command; | ||
} | ||
|
||
var startupCommand = augmentCommandIfNeccessary(fs.readFileSync(CMDFILE, 'utf8').trim()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides pm2 start <process.json>
and node <startScript>
, are there any other startup command formats that could be provided by the user and passed in when the Docker container is run? I'm not aware of any, but I just wanted to confirm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool stuff. This should be a good enhancement for basic scenarios.
console.log("Found scripts.start in package.json") | ||
startupCommand = 'npm start'; | ||
console.log("Found scripts.start in package.json"); | ||
startupCommand = augmentCommandIfNeccessary(json.scripts.start.trim()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming there's no great difference between running npm start
and extracting the command to run it directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only difference that I can think of is that npm start
adds ./node_modules/.bin
to the process' PATH
, and so it's possible that we could introduce issues for apps that depended on that behavior. However, that's typically only used to be able to run executables in the script that are actually installed as a local Node.js module (e.g. webpack
), so I don't think this should be a problem in practice.
The bigger issue might be the assumption that the start script was running node
in the first place, since you could technically put anything else there (e.g. foobar -f server.js
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After thinking about this further, and looking at a set of example apps that have start
scripts, I think this logic is sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better late than never. Another init option for the key is APPLICATIONINSIGHTS_CONNECTION_STRING as seen from the library documentation.
try { | ||
// Initialize the Application Insights runtime, using the | ||
// instrumentation key provided by the environment. | ||
require("applicationinsights").setup().start(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this cause any issues if the user is already doing it in their app?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also - what does this accomplish for your app if you don't have it baked in? I'm assuming it tracks basic metrics?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, doing this init step auto-registers a bunch of metric collection, in order to track telemetry without your app code needing to do anything at all.
If the user was already initializing the AI SDK, then the second call should effectively no-op, but let me verify that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the SDK take any kind of configuration in these calls? If the user is using the SDK, I think their call to it would be the second call (assuming --require would run before anything in the app); if they have done any kind of configuration, that should take precedence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, the app's call to setup().start()
would occur after the bootstrap's script, and therefore, any config that was specified wouldn't take effect unfortunately. That said, the user could provide config via env vars/app settings, which would be automatically picked up/respected by the bootstrap script.
In order to support the scenario where the user chose to auto-enable AI when creating the web app, but also manually added the AI SDK to their app, we may need to make some additional changes to the AI SDK in order to update the config each time the SDK/runtime in initialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nickwalkmsft So I confirmed that all AI SDK config can be overridable in app code (e.g. enabling certain types of auto-collected telemetry), except for the actual instrumentation key. However, the app could work around this by simply setting the APPINSIGHTS_INSTRUMENTATIONKEY
environment variable (which is actually the recommendation for production anyways), and then everything would work as expected, since the env var would naturally be used by the "first" initialization of the AI SDK.
Also, I just had a thought - how does this work on an arbitrary customer app that doesn't use AI? Won't the --require fail since they haven't installed it? |
@nickwalkmsft Since the Docker image itself includes the AI SDK, the |
@nickwalkmsft @naziml Let me know if there's anything else you think should be addressed with this PR. As far as doing some E2E testing, do you think we should just leave this in one Node version and validate the experience a bit further, before replicating it to every Node version? It's already gated behind the |
@nickwalkmsft Should we close this PR for now and re-discuss it in the future? |
Yeah, please go ahead and close. Keep your commits around though; they may be useful later. Thank you! |
This PR updates the base Node.js images, by adding the Application Insights SDK to them. If the Application Insights integration is enabled for the "hosting" web app (resulting in the
ENABLE_APPINSIGHTS
env var being set), then the app's startup command will be augmented in order to transparently initialize the Application Insights runtime in-proc. This way, users can enable AI when creating a web app, do a Git push to a default runtime image, and start immediately collecting telemetry, without needing to do anything further. 🚀If the AI integration feature isn't enabled, then the app will run as usual, with the SDK bits remaining completely inert within the Docker container (similar to the existing default web site bits).
Note: This PR currently only updates the Node
8.1.2
image, in order to get feedback on the implementation. Once the general approach is validated/refined, I'll update the PR to include support for the rest of the default images.// CC @naziml @nickwalkmsft