설명 없음
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ext-dev-usage.js 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.command = void 0;
  4. const Table = require("cli-table");
  5. const clc = require("colorette");
  6. const utils = require("../utils");
  7. const command_1 = require("../command");
  8. const cloudmonitoring_1 = require("../gcp/cloudmonitoring");
  9. const requireAuth_1 = require("../requireAuth");
  10. const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
  11. const metricsUtils_1 = require("../extensions/metricsUtils");
  12. const extensionsApi_1 = require("../extensions/extensionsApi");
  13. const extensionsHelper_1 = require("../extensions/extensionsHelper");
  14. const error_1 = require("../error");
  15. const logger_1 = require("../logger");
  16. const prompt_1 = require("../prompt");
  17. const shortenUrl_1 = require("../shortenUrl");
  18. exports.command = new command_1.Command("ext:dev:usage <publisherId>")
  19. .description("get usage for an extension")
  20. .help("use this command to get the usage of extensions you published. " +
  21. "Specify the publisher ID you used to publish your extensions, " +
  22. "or the extension ref of your published extension.")
  23. .before(requireAuth_1.requireAuth)
  24. .before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
  25. .action(async (input) => {
  26. const extensionRefRegex = /^[\w\d-]+\/[\w\d-]+$/;
  27. let extensionName;
  28. let publisherId;
  29. if (extensionRefRegex.test(input)) {
  30. [publisherId, extensionName] = input.split("/");
  31. }
  32. else {
  33. publisherId = input;
  34. let extensions;
  35. try {
  36. extensions = await (0, extensionsApi_1.listExtensions)(publisherId);
  37. }
  38. catch (err) {
  39. throw new error_1.FirebaseError(err);
  40. }
  41. if (extensions.length < 1) {
  42. throw new error_1.FirebaseError(`There are no published extensions associated with publisher ID ${clc.bold(publisherId)}. This could happen for two reasons:\n` +
  43. " - The publisher ID doesn't exist or could be misspelled\n" +
  44. " - This publisher has not published any extensions\n\n" +
  45. "If you are expecting some extensions to appear, please make sure you have the correct publisher ID and try again.");
  46. }
  47. extensionName = await (0, prompt_1.promptOnce)({
  48. type: "list",
  49. name: "extension",
  50. message: "Which published extension do you want to view the stats for?",
  51. choices: extensions.map((e) => {
  52. const [_, name] = e.ref.split("/");
  53. return {
  54. name,
  55. value: name,
  56. };
  57. }),
  58. });
  59. }
  60. const profile = await (0, extensionsApi_1.getPublisherProfile)("-", publisherId);
  61. const projectNumber = (0, extensionsHelper_1.getPublisherProjectFromName)(profile.name);
  62. const past45d = new Date();
  63. past45d.setDate(past45d.getDate() - 45);
  64. const query = {
  65. filter: `metric.type="firebaseextensions.googleapis.com/extension/version/active_instances" ` +
  66. `resource.type="firebaseextensions.googleapis.com/ExtensionVersion" ` +
  67. `resource.labels.extension="${extensionName}"`,
  68. "interval.endTime": new Date().toJSON(),
  69. "interval.startTime": past45d.toJSON(),
  70. view: cloudmonitoring_1.TimeSeriesView.FULL,
  71. "aggregation.alignmentPeriod": (60 * 60 * 24).toString() + "s",
  72. "aggregation.perSeriesAligner": cloudmonitoring_1.Aligner.ALIGN_MAX,
  73. };
  74. let response;
  75. try {
  76. response = await (0, cloudmonitoring_1.queryTimeSeries)(query, projectNumber);
  77. }
  78. catch (err) {
  79. throw new error_1.FirebaseError(`Error occurred when fetching usage data for extension ${extensionName}`, {
  80. original: err,
  81. });
  82. }
  83. if (!response) {
  84. throw new error_1.FirebaseError(`Couldn't find any usage data for extension ${extensionName}`);
  85. }
  86. const metrics = (0, metricsUtils_1.parseTimeseriesResponse)(response);
  87. const table = new Table({
  88. head: ["Version", "Active Instances", "Changes last 7 Days", "Changes last 28 Days"],
  89. style: {
  90. head: ["yellow"],
  91. },
  92. colAligns: ["left", "right", "right", "right"],
  93. });
  94. metrics.forEach((m) => {
  95. table.push((0, metricsUtils_1.buildMetricsTableRow)(m));
  96. });
  97. utils.logLabeledBullet(extensionsHelper_1.logPrefix, `showing usage stats for ${clc.bold(extensionName)}:`);
  98. logger_1.logger.info(table.toString());
  99. utils.logLabeledBullet(extensionsHelper_1.logPrefix, `How to read this table:`);
  100. logger_1.logger.info(`* Due to privacy considerations, numbers are reported as ranges.`);
  101. logger_1.logger.info(`* In the absence of significant changes, we will render a '-' symbol.`);
  102. logger_1.logger.info(`* You will need more than 10 installs over a period of more than 28 days to render sufficient data.`);
  103. });
  104. async function buildCloudMonitoringLink(args) {
  105. const pageState = {
  106. xyChart: {
  107. dataSets: [
  108. {
  109. timeSeriesFilter: {
  110. filter: `metric.type="firebaseextensions.googleapis.com/extension/version/active_instances"` +
  111. ` resource.type="firebaseextensions.googleapis.com/ExtensionVersion"` +
  112. ` resource.label.extension="${args.extensionName}"`,
  113. minAlignmentPeriod: "86400s",
  114. aggregations: [
  115. {
  116. perSeriesAligner: "ALIGN_MEAN",
  117. crossSeriesReducer: "REDUCE_MAX",
  118. alignmentPeriod: "86400s",
  119. groupByFields: ['resource.label."extension"', 'resource.label."version"'],
  120. },
  121. {
  122. crossSeriesReducer: "REDUCE_NONE",
  123. alignmentPeriod: "60s",
  124. groupByFields: [],
  125. },
  126. ],
  127. },
  128. },
  129. ],
  130. },
  131. isAutoRefresh: true,
  132. timeSelection: {
  133. timeRange: "4w",
  134. },
  135. };
  136. let uri = `https://console.cloud.google.com/monitoring/metrics-explorer?project=${args.projectNumber}` +
  137. `&pageState=${JSON.stringify(pageState)}`;
  138. uri = encodeURI(uri);
  139. uri = await (0, shortenUrl_1.shortenUrl)(uri);
  140. return uri;
  141. }