Skip to content

Commit

Permalink
Report telemetry events for text document services.
Browse files Browse the repository at this point in the history
- Resolves #1066
- Report file extensions, grammar type, and resolver used for didOpen

Signed-off-by: Roland Grunberg <[email protected]>
  • Loading branch information
rgrunber authored and angelozerr committed Aug 9, 2021
1 parent d96343f commit 1883423
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 0 deletions.
5 changes: 5 additions & 0 deletions USAGE_DATA.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ When telemetry events are enabled, the following information is emitted when the
* The free, total, and max VM memory
* Version information:
* The server version number
* Text Document Information
* When a document is opened :
* The file extension (eg. `xml`, `xsd`, `dtd`)
* The associated grammar types (eg. `none`, `doctype`, `xml-model`, `xsi:schemaLocation`, `xsi:noNamespaceSchemaLocation`)
* The resolver used to resolve the grammar identifier (eg. `catalog`, `file association`, `embedded catalog.xsd`, `embedded xml.xsd`, `embedded xslt.xsd`)
* Note: Does NOT include the `JAVA_HOME` environment variable for privacy reasons

Currently, the startup event is the only telemetry event that is emitted.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {

this.parentProcessId = params.getProcessId();

xmlLanguageService.setTelemetryManager(getTelemetryManager());
// Update XML language service extensions with InitializeParams
xmlLanguageService.initializeParams(params);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelHoverParticipant;
import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelSymbolsProviderParticipant;
import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelTypeDefinitionParticipant;
import org.eclipse.lemminx.extensions.contentmodel.participants.DocumentTelemetryParticipant;
import org.eclipse.lemminx.extensions.contentmodel.participants.diagnostics.ContentModelDiagnosticsParticipant;
import org.eclipse.lemminx.extensions.contentmodel.settings.ContentModelSettings;
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings;
Expand Down Expand Up @@ -80,6 +81,8 @@ public class ContentModelPlugin implements IXMLExtension {

private XMLValidationSettings currentValidationSettings;

private DocumentTelemetryParticipant documentTelemetryParticipant;

public ContentModelPlugin() {
completionParticipant = new ContentModelCompletionParticipant();
hoverParticipant = new ContentModelHoverParticipant();
Expand Down Expand Up @@ -184,6 +187,8 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) {
registry.registerSymbolsProviderParticipant(symbolsProviderParticipant);
codeLensParticipant = new ContentModelCodeLensParticipant(contentModelManager);
registry.registerCodeLensParticipant(codeLensParticipant);
documentTelemetryParticipant = new DocumentTelemetryParticipant(registry.getTelemetryManager(), contentModelManager);
registry.registerDocumentLifecycleParticipant(documentTelemetryParticipant);

// Register custom commands to re-validate XML files
IXMLCommandService commandService = registry.getCommandService();
Expand Down Expand Up @@ -211,6 +216,7 @@ public void stop(XMLExtensionsRegistry registry) {
registry.unregisterTypeDefinitionParticipant(typeDefinitionParticipant);
registry.unregisterSymbolsProviderParticipant(symbolsProviderParticipant);
registry.unregisterCodeLensParticipant(codeLensParticipant);
registry.unregisterDocumentLifecycleParticipant(documentTelemetryParticipant);

// Un-register custom commands to re-validate XML files
IXMLCommandService commandService = registry.getCommandService();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.extensions.contentmodel.participants;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager;
import org.eclipse.lemminx.services.extensions.IDocumentLifecycleParticipant;
import org.eclipse.lemminx.telemetry.TelemetryManager;

public class DocumentTelemetryParticipant implements IDocumentLifecycleParticipant {

private TelemetryManager telemetryManager;

private ContentModelManager contentManager;

public DocumentTelemetryParticipant(TelemetryManager telemetryManager, ContentModelManager contentManager) {
this.telemetryManager = telemetryManager;
this.contentManager = contentManager;
}

@Override
public void didOpen(DOMDocument document) {
telemetryManager.onDidOpen(document, contentManager);
}

@Override
public void didChange(DOMDocument document) {}

@Override
public void didSave(DOMDocument document) {}

@Override
public void didClose(DOMDocument document) {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.eclipse.lemminx.services.extensions.format.IFormatterParticipant;
import org.eclipse.lemminx.services.extensions.save.ISaveContext;
import org.eclipse.lemminx.services.extensions.save.ISaveContext.SaveContextType;
import org.eclipse.lemminx.telemetry.TelemetryManager;
import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager;
import org.eclipse.lsp4j.InitializeParams;

Expand Down Expand Up @@ -74,6 +75,8 @@ public class XMLExtensionsRegistry implements IComponentProvider {

private final Map<Class<?>, Object> components;

private TelemetryManager telemetryManager;

public XMLExtensionsRegistry() {
extensions = new ArrayList<>();
completionParticipants = new ArrayList<>();
Expand All @@ -93,6 +96,7 @@ public XMLExtensionsRegistry() {
documentLifecycleParticipants = new ArrayList<>();
resolverExtensionManager = new URIResolverExtensionManager();
components = new HashMap<>();
telemetryManager = new TelemetryManager(null);
registerComponent(resolverExtensionManager);
}

Expand Down Expand Up @@ -505,4 +509,12 @@ public void setCommandService(IXMLCommandService commandService) {
this.commandService = commandService;
}

public TelemetryManager getTelemetryManager() {
return telemetryManager;
}

public void setTelemetryManager(TelemetryManager telemetryManager) {
this.telemetryManager = telemetryManager;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.telemetry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager;
import org.eclipse.lemminx.extensions.contentmodel.model.ReferencedGrammarInfo;

public class DocumentTelemetryInfo {

private static final String DOC_PROP_EXT = "file.extension";
private static final String DOC_PROP_RESOLVER = "file.resolver";
private static final String DOC_PROP_GRAMMAR_NONE = "file.grammar.none";
private static final String DOC_PROP_GRAMMAR_DOCTYPE = "file.grammar.doctype";
private static final String DOC_PROP_GRAMMAR_XMLMODEL = "file.grammar.xmlmodel";
private static final String DOC_PROP_GRAMMAR_SCHEMALOC = "file.grammar.schemalocation";
private static final String DOC_PROP_GRAMMAR_NONSSCHEMALOC = "file.grammar.nonsschemalocation";

public static Map<String, Object> getDocumentTelemetryInfo (DOMDocument doc, ContentModelManager manager) {
String uri = doc.getDocumentURI();
int index = uri.lastIndexOf('.');
String fileExtension = uri.substring(index + 1, uri.length()).toLowerCase();
Set<ReferencedGrammarInfo> referencedGrammarInfos = manager.getReferencedGrammarInfos(doc);
HashMap<String, Object> props = new HashMap<>();
props.put(DOC_PROP_EXT, fileExtension);

if (referencedGrammarInfos.isEmpty()) {
if ("xml".equals(fileExtension)) {
props.put(DOC_PROP_GRAMMAR_NONE, true);
}
} else {
List<String> resolvers = new ArrayList<String>();
for (ReferencedGrammarInfo info : referencedGrammarInfos) {
String kind = info.getBindingKind() == null ? "none" : info.getBindingKind();
String resolver = info.getResolvedBy();
if ("xml".equals(fileExtension)) {
switch (kind) {
case "none":
props.put(DOC_PROP_GRAMMAR_NONE, true);
break;
case "doctype":
props.put(DOC_PROP_GRAMMAR_DOCTYPE, true);
break;
case "xml-model":
props.put(DOC_PROP_GRAMMAR_XMLMODEL, true);
break;
case "xsi:schemaLocation":
props.put(DOC_PROP_GRAMMAR_SCHEMALOC, true);
break;
case "xsi:noNamespaceSchemaLocation":
props.put(DOC_PROP_GRAMMAR_NONSSCHEMALOC, true);
break;
}
}
resolvers.add(resolver == null ? "default" : resolver);
}

props.put(DOC_PROP_RESOLVER, resolvers);
}
return props;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*******************************************************************************/
package org.eclipse.lemminx.telemetry;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager;
import org.eclipse.lsp4j.InitializedParams;
import org.eclipse.lsp4j.services.LanguageClient;

Expand All @@ -24,6 +26,8 @@ public class TelemetryManager {
*/
private static final String STARTUP_EVENT_NAME = "server.initialized";

private static final String DOC_OPEN_EVENT_NAME = "server.document.open";

private final LanguageClient languageClient;

private boolean enabled;
Expand Down Expand Up @@ -51,6 +55,10 @@ public void onInitialized(InitializedParams params) {
}
}

public void onDidOpen(DOMDocument document, ContentModelManager manager) {
telemetryEvent(DOC_OPEN_EVENT_NAME, DocumentTelemetryInfo.getDocumentTelemetryInfo(document, manager));
}

/**
* The telemetry notification is sent from the server to the client to ask the
* client to log a telemetry event.
Expand Down

0 comments on commit 1883423

Please sign in to comment.