Skip to content

Commit 9559efd

Browse files
authored
Adding logging for loading Object Explorer nodes (#18884)
* Adding logging to connection load and OE load paths * adding a little more logging to OE * updating tests * fixing missing mock arg * improving log message
1 parent c0e0fdc commit 9559efd

File tree

9 files changed

+146
-40
lines changed

9 files changed

+146
-40
lines changed

src/connectionconfig/connectionconfig.ts

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,72 +11,117 @@ import { IConnectionConfig } from "./iconnectionconfig";
1111
import VscodeWrapper from "../controllers/vscodeWrapper";
1212
import { Deferred } from "../protocol";
1313
import { ConnectionProfile } from "../models/connectionProfile";
14+
import { Logger } from "../models/logger";
15+
import { getConnectionDisplayName } from "../models/connectionInfo";
1416

1517
/**
1618
* Implements connection profile file storage.
1719
*/
1820
export class ConnectionConfig implements IConnectionConfig {
19-
initialized: Deferred<void> = new Deferred<void>();
21+
private logger: Logger;
2022

23+
initialized: Deferred<void> = new Deferred<void>();
2124
RootGroupName: string = "ROOT";
2225

2326
/**
2427
* Constructor.
2528
*/
2629
public constructor(private _vscodeWrapper?: VscodeWrapper) {
27-
if (!this.vscodeWrapper) {
28-
this.vscodeWrapper = new VscodeWrapper();
30+
if (!this._vscodeWrapper) {
31+
this._vscodeWrapper = new VscodeWrapper();
2932
}
30-
void this.assignMissingIds();
31-
}
3233

33-
private get vscodeWrapper(): VscodeWrapper {
34-
return this._vscodeWrapper;
34+
this.logger = Logger.create(
35+
this._vscodeWrapper.outputChannel,
36+
"ConnectionConfig",
37+
);
38+
39+
void this.assignMissingIds();
3540
}
3641

37-
private set vscodeWrapper(value: VscodeWrapper) {
38-
this._vscodeWrapper = value;
42+
private getRootGroup(): IConnectionGroup | undefined {
43+
const groups: IConnectionGroup[] = this.getGroupsFromSettings();
44+
return groups.find((group) => group.name === this.RootGroupName);
3945
}
4046

4147
private async assignMissingIds(): Promise<void> {
48+
let madeChanges = false;
49+
4250
// Connection groups
4351
const groups: IConnectionGroup[] = this.getGroupsFromSettings();
4452

45-
// ensure each group has an id
46-
groups.forEach((group) => {
47-
if (!group.id) {
48-
group.id = Utils.generateGuid();
49-
}
50-
});
51-
5253
// ensure ROOT group exists
53-
let rootGroup = groups.find(
54-
(group) => group.name === this.RootGroupName,
55-
);
54+
let rootGroup = this.getRootGroup();
55+
5656
if (!rootGroup) {
5757
rootGroup = {
5858
name: this.RootGroupName,
5959
id: Utils.generateGuid(),
6060
};
61+
62+
this.logger.logDebug(
63+
`Adding missing ROOT group to connection groups`,
64+
);
65+
madeChanges = true;
6166
groups.push(rootGroup);
6267
}
6368

69+
// Clean up connection groups
70+
for (const group of groups) {
71+
if (group.id === rootGroup.id) {
72+
continue;
73+
}
74+
75+
// ensure each group has an ID
76+
if (!group.id) {
77+
group.id = Utils.generateGuid();
78+
madeChanges = true;
79+
this.logger.logDebug(
80+
`Adding missing ID to connection group '${group.name}'`,
81+
);
82+
}
83+
84+
// ensure each group is in a group
85+
if (!group.groupId) {
86+
group.groupId = rootGroup.id;
87+
madeChanges = true;
88+
this.logger.logDebug(
89+
`Adding missing parentId to connection '${group.name}'`,
90+
);
91+
}
92+
}
93+
6494
// Clean up connection profiles
6595
const profiles: IConnectionProfile[] = this.getProfilesFromSettings();
6696

67-
profiles.forEach((profile) => {
68-
// ensure each profile has an id
69-
ConnectionProfile.addIdIfMissing(profile);
97+
for (const profile of profiles) {
98+
// ensure each profile has an ID
99+
if (ConnectionProfile.addIdIfMissing(profile)) {
100+
madeChanges = true;
101+
this.logger.logDebug(
102+
`Adding missing ID to connection '${getConnectionDisplayName(profile)}'`,
103+
);
104+
}
70105

71106
// ensure each profile is in a group
72107
if (!profile.groupId) {
73108
profile.groupId = rootGroup.id;
109+
madeChanges = true;
110+
this.logger.logDebug(
111+
`Adding missing groupId to connection '${getConnectionDisplayName(profile)}'`,
112+
);
74113
}
75-
});
114+
}
76115

77116
// Save the changes to settings
78-
await this.writeConnectionGroupsToSettings(groups);
79-
await this.writeProfilesToSettings(profiles);
117+
if (madeChanges) {
118+
this.logger.logDebug(
119+
`Updates made to connection profiles and groups. Writing all ${groups.length} group(s) and ${profiles.length} profile(s) to settings.`,
120+
);
121+
122+
await this.writeConnectionGroupsToSettings(groups);
123+
await this.writeProfilesToSettings(profiles);
124+
}
80125

81126
this.initialized.resolve();
82127
}
@@ -85,6 +130,13 @@ export class ConnectionConfig implements IConnectionConfig {
85130
* Add a new connection to the connection config.
86131
*/
87132
public async addConnection(profile: IConnectionProfile): Promise<void> {
133+
if (profile.groupId === undefined) {
134+
const rootGroup = this.getRootGroup();
135+
if (rootGroup) {
136+
profile.groupId = rootGroup.id;
137+
}
138+
}
139+
88140
let profiles = this.getProfilesFromSettings();
89141

90142
// Remove the profile if already set

src/controllers/mainController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ export default class MainController implements vscode.Disposable {
738738
const self = this;
739739
// Register the object explorer tree provider
740740
this._objectExplorerProvider = new ObjectExplorerProvider(
741+
this._vscodeWrapper,
741742
this._connectionMgr,
742743
);
743744
this.objectExplorerTree = vscode.window.createTreeView(

src/models/connectionProfile.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export class ConnectionProfile
6262
this.server = connectionCredentials.server;
6363
}
6464
}
65+
6566
/**
6667
* Creates a new profile by prompting the user for information.
6768
* @param prompter that asks user the questions needed to complete a profile
@@ -219,10 +220,13 @@ export class ConnectionProfile
219220
return undefined;
220221
}
221222

222-
public static addIdIfMissing(profile: IConnectionProfile): void {
223+
public static addIdIfMissing(profile: IConnectionProfile): boolean {
223224
if (profile && profile.id === undefined) {
224225
profile.id = utils.generateGuid();
226+
return true;
225227
}
228+
229+
return false;
226230
}
227231

228232
// Assumption: having connection string or server + profile name indicates all requirements were met

src/models/connectionStore.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,10 @@ export class ConnectionStore {
643643

644644
// TODO re-add deduplication logic from old method
645645

646+
this._logger.logDebug(
647+
`readAllConnections: ${connResults.length} connections${includeRecentConnections ? ` (${configConnections.length} from config, ${connResults.length - configConnections.length} from recent)` : "; excluded recent"})`,
648+
);
649+
646650
return connResults;
647651
}
648652

src/models/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export interface IConnectionProfile extends vscodeMssql.IConnectionInfo {
7373
export interface IConnectionGroup {
7474
id: string;
7575
name: string;
76-
parentId?: string;
76+
groupId?: string;
7777
color?: string;
7878
description?: string;
7979
}

src/models/logger.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,13 @@ export class Logger implements ILogger {
9595
return this._piiLogging;
9696
}
9797

98-
/** If `mssql.logDebug` is enabled, prints the message to the developer console */
98+
/**
99+
* Prints at the `verbose` level.
100+
* If `mssql.logDebug` is enabled, prints the message to the developer console.
101+
**/
99102
public logDebug(message: string): void {
100103
Utils.logDebug(message);
104+
this.write(LogLevel.Verbose, message);
101105
}
102106

103107
public critical(msg: any, ...vals: any[]): void {

src/objectExplorer/objectExplorerProvider.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ObjectExplorerService } from "./objectExplorerService";
99
import { TreeNodeInfo } from "./treeNodeInfo";
1010
import { Deferred } from "../protocol";
1111
import { IConnectionInfo } from "vscode-mssql";
12+
import VscodeWrapper from "../controllers/vscodeWrapper";
1213

1314
export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
1415
private _onDidChangeTreeData: vscode.EventEmitter<any | undefined> =
@@ -19,8 +20,16 @@ export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
1920
private _objectExplorerExists: boolean;
2021
private _objectExplorerService: ObjectExplorerService;
2122

22-
constructor(connectionManager: ConnectionManager) {
23+
constructor(
24+
private _vscodeWrapper: VscodeWrapper,
25+
connectionManager: ConnectionManager,
26+
) {
27+
if (!_vscodeWrapper) {
28+
this._vscodeWrapper = new VscodeWrapper();
29+
}
30+
2331
this._objectExplorerService = new ObjectExplorerService(
32+
this._vscodeWrapper,
2433
connectionManager,
2534
this,
2635
);

src/objectExplorer/objectExplorerService.ts

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ import {
5656
GetSessionIdRequest,
5757
GetSessionIdResponse,
5858
} from "../models/contracts/objectExplorer/getSessionIdRequest";
59+
import { Logger } from "../models/logger";
60+
import VscodeWrapper from "../controllers/vscodeWrapper";
5961

6062
function getParentNode(node: TreeNodeType): TreeNodeInfo {
6163
node = node.parentNode;
@@ -68,6 +70,7 @@ function getParentNode(node: TreeNodeType): TreeNodeInfo {
6870

6971
export class ObjectExplorerService {
7072
private _client: SqlToolsServiceClient;
73+
private _logger: Logger;
7174
private _currentNode: TreeNodeInfo;
7275
private _treeNodeToChildrenMap: Map<vscode.TreeItem, vscode.TreeItem[]>;
7376
private _sessionIdToNodeLabelMap: Map<string, string>;
@@ -83,10 +86,21 @@ export class ObjectExplorerService {
8386
>;
8487

8588
constructor(
89+
private _vscodeWrapper: VscodeWrapper,
8690
private _connectionManager: ConnectionManager,
8791
private _objectExplorerProvider: ObjectExplorerProvider,
8892
) {
93+
if (!_vscodeWrapper) {
94+
this._vscodeWrapper = new VscodeWrapper();
95+
}
96+
8997
this._client = this._connectionManager.client;
98+
99+
this._logger = Logger.create(
100+
this._vscodeWrapper.outputChannel,
101+
"ObjectExplorerService",
102+
);
103+
90104
this._treeNodeToChildrenMap = new Map<
91105
vscode.TreeItem,
92106
vscode.TreeItem[]
@@ -581,7 +595,7 @@ export class ObjectExplorerService {
581595
}
582596

583597
/**
584-
* Helper to show the Add Connection node
598+
* Helper to show the Add Connection node; only displayed when there are no saved connections
585599
*/
586600
private getAddConnectionNode(): AddConnectionTreeNode[] {
587601
this._rootTreeNodeArray = [];
@@ -611,6 +625,10 @@ export class ObjectExplorerService {
611625

612626
async getChildren(element?: TreeNodeInfo): Promise<vscode.TreeItem[]> {
613627
if (element) {
628+
this._logger.logDebug(
629+
`Getting children for node '${element.nodePath}'`,
630+
);
631+
614632
// set current node for very first expansion of disconnected node
615633
if (this._currentNode !== element) {
616634
this._currentNode = element;
@@ -668,24 +686,34 @@ export class ObjectExplorerService {
668686
}
669687
}
670688
} else {
671-
// retrieve saved connections first when opening object explorer
672-
// for the first time
689+
this._logger.logDebug("Getting root OE nodes");
690+
691+
// retrieve saved connections first when opening object explorer for the first time
673692
let savedConnections =
674693
this._connectionManager.connectionStore.readAllConnections();
675-
// if there are no saved connections
676-
// show the add connection node
694+
695+
// if there are no saved connections, show the add connection node
677696
if (savedConnections.length === 0) {
697+
this._logger.logDebug(
698+
"No saved connections found; displaying 'Add Connection' node",
699+
);
678700
return this.getAddConnectionNode();
679701
}
680-
// if OE doesn't exist the first time
681-
// then build the nodes off of saved connections
702+
703+
// if OE doesn't exist the first time, then build the nodes off of saved connections
682704
if (!this._objectExplorerProvider.objectExplorerExists) {
683705
// if there are actually saved connections
684706
this._rootTreeNodeArray = [];
685707
await this.addSavedNodesConnectionsToRoot();
708+
this._logger.logDebug(
709+
`No current OE; added ${this._rootTreeNodeArray.length} nodes to OE root`,
710+
);
686711
this._objectExplorerProvider.objectExplorerExists = true;
687712
return this.sortByServerName(this._rootTreeNodeArray);
688713
} else {
714+
this._logger.logDebug(
715+
`Returning cached OE root nodes (${this._rootTreeNodeArray.length})`,
716+
);
689717
// otherwise returned the cached nodes
690718
return this.sortByServerName(this._rootTreeNodeArray);
691719
}
@@ -1085,7 +1113,8 @@ export class ObjectExplorerService {
10851113
}
10861114
}
10871115

1088-
/** Getters */
1116+
//#region Getters and Setters
1117+
10891118
public get currentNode(): TreeNodeInfo {
10901119
return this._currentNode;
10911120
}
@@ -1101,10 +1130,9 @@ export class ObjectExplorerService {
11011130
return connections;
11021131
}
11031132

1104-
/**
1105-
* Setters
1106-
*/
11071133
public set currentNode(node: TreeNodeInfo) {
11081134
this._currentNode = node;
11091135
}
1136+
1137+
//#endregion
11101138
}

0 commit comments

Comments
 (0)