Skip to content

Commit 3e28f26

Browse files
[AzureSpringCloudV0] Print app logs when deployment failed (#19153)
* Print app logs when deployment failed --------- Co-authored-by: Martin Mrazik <[email protected]>
1 parent 6f75e15 commit 3e28f26

File tree

4 files changed

+138
-44
lines changed

4 files changed

+138
-44
lines changed

Tasks/AzureSpringCloudV0/deploymentProvider/azure-arm-spring-apps.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,26 @@ export class AzureSpringApps {
7878
return this._client.beginRequest(httpRequest);
7979
}
8080

81+
/**
82+
* send request using webClient.sendRequest
83+
* @param method
84+
* @param url
85+
* @param body
86+
* @param headers
87+
* @returns webClient.WebResponse
88+
*/
89+
protected sendRequestV2(method: string, url: string, body?: any, headers?: any): Promise<webClient.WebResponse> {
90+
var httpRequest = new webClient.WebRequest();
91+
httpRequest.method = method;
92+
httpRequest.uri = url;
93+
if (body)
94+
httpRequest.body = body;
95+
if (headers)
96+
httpRequest.headers = headers;
97+
tl.debug(`Sending ${method} request to ${url}`);
98+
return webClient.sendRequest(httpRequest);
99+
}
100+
81101
/**
82102
* Deploys an artifact to an Azure Spring Cloud deployment
83103
* @param artifactToUpload
@@ -322,6 +342,30 @@ export class AzureSpringApps {
322342
}
323343
}
324344

345+
protected async getDeploymentInfo(appName: String, deploymentName: String): Promise<Object> {
346+
tl.debug(`Query deployment ${deploymentName} for app ${appName}`)
347+
const requestUri = this._client.getRequestUri(`${this._resourceId}/apps/{appName}/deployments/{deploymentName}`, {
348+
'{appName}': appName,
349+
'{deploymentName}': deploymentName
350+
}, null, API_VERSION);
351+
352+
try {
353+
const response = await this.sendRequest('GET', requestUri);
354+
if (response.statusCode == 404) {
355+
tl.debug(`404 when querying deployment ${deploymentName} for app ${appName}`);
356+
throw Error(tl.loc('NoDeploymentsExist'));
357+
} if (response.statusCode != 200) {
358+
tl.error(`${tl.loc('UnableToGetDeploymentInformation')} ${tl.loc('StatusCode')}: ${response.statusCode}`);
359+
throw ToError(response);
360+
} else {
361+
tl.debug('Found deployment ${deploymentName} for app ${appName}.');
362+
return response.body;
363+
}
364+
} catch (error) {
365+
throw (error);
366+
}
367+
}
368+
325369
/**
326370
* Returns the currently inactive deployment, or `undefined` if none exists.
327371
* @param appName
@@ -477,6 +521,7 @@ export class AzureSpringApps {
477521
var response = await this.sendRequest(method, requestUri, JSON.stringify(deploymentUpdateRequestBody));
478522
} catch (error) {
479523
tl.debug('Error when sending app update request');
524+
await this.printLatestAppInstanceLog(appName, deploymentName);
480525
throw (error);
481526
}
482527
console.log(JSON.stringify(response.body, null, 2));
@@ -496,6 +541,7 @@ export class AzureSpringApps {
496541
await this.awaitOperationCompletion(operationStatusUrl);
497542
} catch (error) {
498543
tl.debug('Error in awaiting operation completion');
544+
await this.printLatestAppInstanceLog(appName, deploymentName);
499545
throw error;
500546
} finally {
501547
//A build log is available on the deployment when uploading a folder. Let's display it.
@@ -650,4 +696,51 @@ export class AzureSpringApps {
650696
throw (error);
651697
}
652698
}
699+
700+
private async printLatestAppInstanceLog(appName: string, deploymentName: string) {
701+
console.info('Some error occured during deployment. Printing latest app instance log:');
702+
const logStream = await this.logStreamConstructor();
703+
const deploymentResource = await this.getDeploymentInfo(appName, deploymentName);
704+
const instances = deploymentResource["properties"]["instances"];
705+
let startTime = instances[0].startTime;
706+
let instanceName = instances[0].name;
707+
708+
// print the newly created instance log
709+
for (const tempInstance of instances) {
710+
if (tempInstance.startTime > startTime) {
711+
startTime = tempInstance.startTime;
712+
instanceName = tempInstance.name;
713+
}
714+
}
715+
let streamingUrl = `https://${logStream["baseUrl"]}/api/logstream/apps/${appName}/instances/${instanceName}?follow=true`;
716+
const credentials = Buffer.from(`primary:${logStream["primaryKey"]}`).toString('base64');
717+
const headers = {
718+
"Authorization" : `Basic ${credentials}`
719+
};
720+
await this.sendRequestV2('GET', streamingUrl, null, headers).then(response => {
721+
console.info(response.body);
722+
});
723+
}
724+
725+
public async logStreamConstructor() {
726+
tl.debug("Constructing log stream");
727+
let ret = {};
728+
let requestUri = this._client.getRequestUri(`${this._resourceId}/listTestKeys`, {}, null, API_VERSION);
729+
try {
730+
var response: webClient.WebResponse = await this.sendRequest('POST', requestUri);
731+
if (!response.body.enabled) {
732+
tl.warning(tl.loc('PrivateTestEndpointNotEnabled but log stream needs it'));
733+
return null;
734+
} else {
735+
tl.debug('log stream constructed.');
736+
ret["primaryKey"] = response.body.primaryKey;
737+
}
738+
} catch (error) {
739+
tl.error(tl.loc('UnableToRetrieveTestEndpointKeys'));
740+
throw (error);
741+
}
742+
const serviceResponse = await this.getServiceInfo();
743+
ret["baseUrl"] = serviceResponse["properties"]["fqdn"];
744+
return ret;
745+
}
653746
}

0 commit comments

Comments
 (0)