@be-link/cls-logger 1.0.1-beta.25 → 1.0.1-beta.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/web.esm.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as tencentcloudClsSdkJsWeb from 'tencentcloud-cls-sdk-js-web';
2
- import { onFCP, onLCP, onCLS, onINP, onTTFB } from 'web-vitals';
3
2
 
4
3
  function isPlainObject(value) {
5
4
  return Object.prototype.toString.call(value) === '[object Object]';
@@ -1465,10 +1464,14 @@ function getPagePath() {
1465
1464
  return '';
1466
1465
  }
1467
1466
  }
1468
- /**
1469
- * 安装浏览器性能监控
1470
- * 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
1471
- */
1467
+ function reportMetric(report, reportType, metric, value, extra = {}) {
1468
+ report(reportType, {
1469
+ pagePath: getPagePath(),
1470
+ metric,
1471
+ value,
1472
+ ...extra,
1473
+ });
1474
+ }
1472
1475
  function installBrowserPerformanceMonitor(report, options) {
1473
1476
  if (typeof window === 'undefined')
1474
1477
  return;
@@ -1477,100 +1480,145 @@ function installBrowserPerformanceMonitor(report, options) {
1477
1480
  return;
1478
1481
  w.__beLinkClsLoggerPerfInstalled__ = true;
1479
1482
  const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
1480
- // Web Vitals: 使用 Google web-vitals 库
1481
- // 这个库会自动处理:
1482
- // - LCP 在用户交互后停止观察
1483
- // - firstHiddenTime 过滤(页面隐藏后的数据不计入)
1484
- // - CLS 5秒会话窗口算法
1485
- // - BFCache 恢复时自动重置指标
1486
- if (options.webVitals) {
1487
- // FCP
1483
+ // Navigation timing: TTFB
1484
+ if (options.navigationTiming) {
1488
1485
  try {
1489
- onFCP((metric) => {
1490
- report(options.reportType, {
1491
- pagePath: getPagePath(),
1492
- metric: 'FCP',
1493
- value: metric.value,
1494
- unit: 'ms',
1495
- rating: metric.rating,
1496
- id: metric.id,
1497
- navigationType: metric.navigationType,
1498
- });
1499
- });
1486
+ const navEntries = performance.getEntriesByType?.('navigation');
1487
+ const nav = Array.isArray(navEntries) ? navEntries[0] : undefined;
1488
+ if (nav && typeof nav === 'object') {
1489
+ const ttfb = typeof nav.responseStart === 'number' && typeof nav.requestStart === 'number'
1490
+ ? nav.responseStart - nav.requestStart
1491
+ : -1;
1492
+ if (ttfb >= 0 && sampleHit(options.sampleRate))
1493
+ reportMetric(report, options.reportType, 'TTFB', ttfb, { unit: 'ms' });
1494
+ }
1500
1495
  }
1501
1496
  catch {
1502
1497
  // ignore
1503
1498
  }
1504
- // LCP(自动处理用户交互后停止)
1499
+ }
1500
+ // Web Vitals: FCP/LCP/CLS/FID
1501
+ if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
1502
+ // FCP
1505
1503
  try {
1506
- onLCP((metric) => {
1507
- report(options.reportType, {
1508
- pagePath: getPagePath(),
1509
- metric: 'LCP',
1510
- value: metric.value,
1511
- unit: 'ms',
1512
- rating: metric.rating,
1513
- id: metric.id,
1514
- navigationType: metric.navigationType,
1515
- });
1504
+ const po = new PerformanceObserver((list) => {
1505
+ try {
1506
+ if (!sampleHit(options.sampleRate))
1507
+ return;
1508
+ for (const entry of list.getEntries()) {
1509
+ if (entry?.name === 'first-contentful-paint' && typeof entry.startTime === 'number') {
1510
+ reportMetric(report, options.reportType, 'FCP', entry.startTime, { unit: 'ms' });
1511
+ }
1512
+ }
1513
+ }
1514
+ catch {
1515
+ // ignore
1516
+ }
1516
1517
  });
1518
+ po.observe({ type: 'paint', buffered: true });
1517
1519
  }
1518
1520
  catch {
1519
1521
  // ignore
1520
1522
  }
1521
- // CLS(自动处理会话窗口)
1523
+ // LCP(最后一次为准)
1524
+ let lastLcp = null;
1522
1525
  try {
1523
- onCLS((metric) => {
1524
- report(options.reportType, {
1525
- pagePath: getPagePath(),
1526
- metric: 'CLS',
1527
- value: metric.value,
1528
- unit: 'score',
1529
- rating: metric.rating,
1530
- id: metric.id,
1531
- navigationType: metric.navigationType,
1532
- });
1526
+ const po = new PerformanceObserver((list) => {
1527
+ try {
1528
+ const entries = list.getEntries();
1529
+ if (entries && entries.length)
1530
+ lastLcp = entries[entries.length - 1];
1531
+ }
1532
+ catch {
1533
+ // ignore
1534
+ }
1533
1535
  });
1536
+ po.observe({ type: 'largest-contentful-paint', buffered: true });
1537
+ const flushLcp = () => {
1538
+ try {
1539
+ if (!lastLcp)
1540
+ return;
1541
+ if (!sampleHit(options.sampleRate))
1542
+ return;
1543
+ if (typeof lastLcp.startTime === 'number')
1544
+ reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
1545
+ lastLcp = null;
1546
+ }
1547
+ catch {
1548
+ // ignore
1549
+ }
1550
+ };
1551
+ window.addEventListener('pagehide', flushLcp, { once: true });
1552
+ document.addEventListener('visibilitychange', () => {
1553
+ if (document.visibilityState === 'hidden')
1554
+ flushLcp();
1555
+ }, { once: true });
1534
1556
  }
1535
1557
  catch {
1536
1558
  // ignore
1537
1559
  }
1538
- // INP(替代 FID,2024年3月起成为核心指标)
1560
+ // CLS
1539
1561
  try {
1540
- onINP((metric) => {
1541
- report(options.reportType, {
1542
- pagePath: getPagePath(),
1543
- metric: 'INP',
1544
- value: metric.value,
1545
- unit: 'ms',
1546
- rating: metric.rating,
1547
- id: metric.id,
1548
- navigationType: metric.navigationType,
1549
- });
1562
+ let clsValue = 0;
1563
+ const po = new PerformanceObserver((list) => {
1564
+ try {
1565
+ for (const entry of list.getEntries()) {
1566
+ if (entry && entry.hadRecentInput)
1567
+ continue;
1568
+ if (typeof entry.value === 'number')
1569
+ clsValue += entry.value;
1570
+ }
1571
+ }
1572
+ catch {
1573
+ // ignore
1574
+ }
1550
1575
  });
1576
+ po.observe({ type: 'layout-shift', buffered: true });
1577
+ const flushCls = () => {
1578
+ try {
1579
+ if (!sampleHit(options.sampleRate))
1580
+ return;
1581
+ reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
1582
+ }
1583
+ catch {
1584
+ // ignore
1585
+ }
1586
+ };
1587
+ window.addEventListener('pagehide', flushCls, { once: true });
1588
+ document.addEventListener('visibilitychange', () => {
1589
+ if (document.visibilityState === 'hidden')
1590
+ flushCls();
1591
+ }, { once: true });
1551
1592
  }
1552
1593
  catch {
1553
1594
  // ignore
1554
1595
  }
1555
- // TTFB
1596
+ // FID
1556
1597
  try {
1557
- onTTFB((metric) => {
1558
- report(options.reportType, {
1559
- pagePath: getPagePath(),
1560
- metric: 'TTFB',
1561
- value: metric.value,
1562
- unit: 'ms',
1563
- rating: metric.rating,
1564
- id: metric.id,
1565
- navigationType: metric.navigationType,
1566
- });
1598
+ const po = new PerformanceObserver((list) => {
1599
+ try {
1600
+ if (!sampleHit(options.sampleRate))
1601
+ return;
1602
+ for (const entry of list.getEntries()) {
1603
+ const startTime = typeof entry.startTime === 'number' ? entry.startTime : -1;
1604
+ const processingStart = typeof entry.processingStart === 'number' ? entry.processingStart : -1;
1605
+ if (startTime >= 0 && processingStart >= 0) {
1606
+ reportMetric(report, options.reportType, 'FID', processingStart - startTime, { unit: 'ms' });
1607
+ break;
1608
+ }
1609
+ }
1610
+ }
1611
+ catch {
1612
+ // ignore
1613
+ }
1567
1614
  });
1615
+ po.observe({ type: 'first-input', buffered: true });
1568
1616
  }
1569
1617
  catch {
1570
1618
  // ignore
1571
1619
  }
1572
1620
  }
1573
- // Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
1621
+ // Resource timing:资源加载耗时
1574
1622
  if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
1575
1623
  try {
1576
1624
  const po = new PerformanceObserver((list) => {
@@ -1655,6 +1703,7 @@ function installWebPerformanceMonitor(report, opts = {}) {
1655
1703
  sampleRate: raw.sampleRate ?? 1,
1656
1704
  ignoreUrls: raw.ignoreUrls ?? [],
1657
1705
  webVitals: raw.webVitals ?? true,
1706
+ navigationTiming: raw.navigationTiming ?? true,
1658
1707
  resourceTiming: raw.resourceTiming ?? true,
1659
1708
  maxTextLength: raw.maxTextLength ?? 2000,
1660
1709
  };
@@ -2030,6 +2079,43 @@ function getBrowserDeviceInfo(options) {
2030
2079
  // ignore
2031
2080
  }
2032
2081
  }
2082
+ if (options.includeNetworkType) {
2083
+ try {
2084
+ const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
2085
+ if (conn && isPlainObject(conn)) {
2086
+ const type = conn.type;
2087
+ const eff = conn.effectiveType;
2088
+ let val = '';
2089
+ if (type === 'wifi' || type === 'ethernet') {
2090
+ val = 'WIFI';
2091
+ }
2092
+ else if (type === 'cellular' || type === 'wimax') {
2093
+ if (eff === 'slow-2g' || eff === '2g')
2094
+ val = '2G';
2095
+ else if (eff === '3g')
2096
+ val = '3G';
2097
+ else if (eff === '4g')
2098
+ val = '4G';
2099
+ else
2100
+ val = '4G';
2101
+ }
2102
+ else {
2103
+ // type 未知或不支持,降级使用 effectiveType
2104
+ if (eff === 'slow-2g' || eff === '2g')
2105
+ val = '2G';
2106
+ else if (eff === '3g')
2107
+ val = '3G';
2108
+ else if (eff === '4g')
2109
+ val = '4G';
2110
+ }
2111
+ if (val)
2112
+ out.networkType = val;
2113
+ }
2114
+ }
2115
+ catch {
2116
+ // ignore
2117
+ }
2118
+ }
2033
2119
  return out;
2034
2120
  }
2035
2121
  function createWebDeviceInfoBaseFields(opts) {
package/dist/web.js CHANGED
@@ -3,7 +3,6 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tencentcloudClsSdkJsWeb = require('tencentcloud-cls-sdk-js-web');
6
- var webVitals = require('web-vitals');
7
6
 
8
7
  function _interopNamespaceDefault(e) {
9
8
  var n = Object.create(null);
@@ -1488,10 +1487,14 @@ function getPagePath() {
1488
1487
  return '';
1489
1488
  }
1490
1489
  }
1491
- /**
1492
- * 安装浏览器性能监控
1493
- * 使用 Google web-vitals 库实现 Core Web Vitals 指标采集
1494
- */
1490
+ function reportMetric(report, reportType, metric, value, extra = {}) {
1491
+ report(reportType, {
1492
+ pagePath: getPagePath(),
1493
+ metric,
1494
+ value,
1495
+ ...extra,
1496
+ });
1497
+ }
1495
1498
  function installBrowserPerformanceMonitor(report, options) {
1496
1499
  if (typeof window === 'undefined')
1497
1500
  return;
@@ -1500,100 +1503,145 @@ function installBrowserPerformanceMonitor(report, options) {
1500
1503
  return;
1501
1504
  w.__beLinkClsLoggerPerfInstalled__ = true;
1502
1505
  const ignoreUrls = [...DEFAULT_IGNORE, ...(options.ignoreUrls ?? [])];
1503
- // Web Vitals: 使用 Google web-vitals 库
1504
- // 这个库会自动处理:
1505
- // - LCP 在用户交互后停止观察
1506
- // - firstHiddenTime 过滤(页面隐藏后的数据不计入)
1507
- // - CLS 5秒会话窗口算法
1508
- // - BFCache 恢复时自动重置指标
1509
- if (options.webVitals) {
1510
- // FCP
1506
+ // Navigation timing: TTFB
1507
+ if (options.navigationTiming) {
1511
1508
  try {
1512
- webVitals.onFCP((metric) => {
1513
- report(options.reportType, {
1514
- pagePath: getPagePath(),
1515
- metric: 'FCP',
1516
- value: metric.value,
1517
- unit: 'ms',
1518
- rating: metric.rating,
1519
- id: metric.id,
1520
- navigationType: metric.navigationType,
1521
- });
1522
- });
1509
+ const navEntries = performance.getEntriesByType?.('navigation');
1510
+ const nav = Array.isArray(navEntries) ? navEntries[0] : undefined;
1511
+ if (nav && typeof nav === 'object') {
1512
+ const ttfb = typeof nav.responseStart === 'number' && typeof nav.requestStart === 'number'
1513
+ ? nav.responseStart - nav.requestStart
1514
+ : -1;
1515
+ if (ttfb >= 0 && sampleHit(options.sampleRate))
1516
+ reportMetric(report, options.reportType, 'TTFB', ttfb, { unit: 'ms' });
1517
+ }
1523
1518
  }
1524
1519
  catch {
1525
1520
  // ignore
1526
1521
  }
1527
- // LCP(自动处理用户交互后停止)
1522
+ }
1523
+ // Web Vitals: FCP/LCP/CLS/FID
1524
+ if (options.webVitals && typeof globalThis.PerformanceObserver === 'function') {
1525
+ // FCP
1528
1526
  try {
1529
- webVitals.onLCP((metric) => {
1530
- report(options.reportType, {
1531
- pagePath: getPagePath(),
1532
- metric: 'LCP',
1533
- value: metric.value,
1534
- unit: 'ms',
1535
- rating: metric.rating,
1536
- id: metric.id,
1537
- navigationType: metric.navigationType,
1538
- });
1527
+ const po = new PerformanceObserver((list) => {
1528
+ try {
1529
+ if (!sampleHit(options.sampleRate))
1530
+ return;
1531
+ for (const entry of list.getEntries()) {
1532
+ if (entry?.name === 'first-contentful-paint' && typeof entry.startTime === 'number') {
1533
+ reportMetric(report, options.reportType, 'FCP', entry.startTime, { unit: 'ms' });
1534
+ }
1535
+ }
1536
+ }
1537
+ catch {
1538
+ // ignore
1539
+ }
1539
1540
  });
1541
+ po.observe({ type: 'paint', buffered: true });
1540
1542
  }
1541
1543
  catch {
1542
1544
  // ignore
1543
1545
  }
1544
- // CLS(自动处理会话窗口)
1546
+ // LCP(最后一次为准)
1547
+ let lastLcp = null;
1545
1548
  try {
1546
- webVitals.onCLS((metric) => {
1547
- report(options.reportType, {
1548
- pagePath: getPagePath(),
1549
- metric: 'CLS',
1550
- value: metric.value,
1551
- unit: 'score',
1552
- rating: metric.rating,
1553
- id: metric.id,
1554
- navigationType: metric.navigationType,
1555
- });
1549
+ const po = new PerformanceObserver((list) => {
1550
+ try {
1551
+ const entries = list.getEntries();
1552
+ if (entries && entries.length)
1553
+ lastLcp = entries[entries.length - 1];
1554
+ }
1555
+ catch {
1556
+ // ignore
1557
+ }
1556
1558
  });
1559
+ po.observe({ type: 'largest-contentful-paint', buffered: true });
1560
+ const flushLcp = () => {
1561
+ try {
1562
+ if (!lastLcp)
1563
+ return;
1564
+ if (!sampleHit(options.sampleRate))
1565
+ return;
1566
+ if (typeof lastLcp.startTime === 'number')
1567
+ reportMetric(report, options.reportType, 'LCP', lastLcp.startTime, { unit: 'ms' });
1568
+ lastLcp = null;
1569
+ }
1570
+ catch {
1571
+ // ignore
1572
+ }
1573
+ };
1574
+ window.addEventListener('pagehide', flushLcp, { once: true });
1575
+ document.addEventListener('visibilitychange', () => {
1576
+ if (document.visibilityState === 'hidden')
1577
+ flushLcp();
1578
+ }, { once: true });
1557
1579
  }
1558
1580
  catch {
1559
1581
  // ignore
1560
1582
  }
1561
- // INP(替代 FID,2024年3月起成为核心指标)
1583
+ // CLS
1562
1584
  try {
1563
- webVitals.onINP((metric) => {
1564
- report(options.reportType, {
1565
- pagePath: getPagePath(),
1566
- metric: 'INP',
1567
- value: metric.value,
1568
- unit: 'ms',
1569
- rating: metric.rating,
1570
- id: metric.id,
1571
- navigationType: metric.navigationType,
1572
- });
1585
+ let clsValue = 0;
1586
+ const po = new PerformanceObserver((list) => {
1587
+ try {
1588
+ for (const entry of list.getEntries()) {
1589
+ if (entry && entry.hadRecentInput)
1590
+ continue;
1591
+ if (typeof entry.value === 'number')
1592
+ clsValue += entry.value;
1593
+ }
1594
+ }
1595
+ catch {
1596
+ // ignore
1597
+ }
1573
1598
  });
1599
+ po.observe({ type: 'layout-shift', buffered: true });
1600
+ const flushCls = () => {
1601
+ try {
1602
+ if (!sampleHit(options.sampleRate))
1603
+ return;
1604
+ reportMetric(report, options.reportType, 'CLS', clsValue, { unit: 'score' });
1605
+ }
1606
+ catch {
1607
+ // ignore
1608
+ }
1609
+ };
1610
+ window.addEventListener('pagehide', flushCls, { once: true });
1611
+ document.addEventListener('visibilitychange', () => {
1612
+ if (document.visibilityState === 'hidden')
1613
+ flushCls();
1614
+ }, { once: true });
1574
1615
  }
1575
1616
  catch {
1576
1617
  // ignore
1577
1618
  }
1578
- // TTFB
1619
+ // FID
1579
1620
  try {
1580
- webVitals.onTTFB((metric) => {
1581
- report(options.reportType, {
1582
- pagePath: getPagePath(),
1583
- metric: 'TTFB',
1584
- value: metric.value,
1585
- unit: 'ms',
1586
- rating: metric.rating,
1587
- id: metric.id,
1588
- navigationType: metric.navigationType,
1589
- });
1621
+ const po = new PerformanceObserver((list) => {
1622
+ try {
1623
+ if (!sampleHit(options.sampleRate))
1624
+ return;
1625
+ for (const entry of list.getEntries()) {
1626
+ const startTime = typeof entry.startTime === 'number' ? entry.startTime : -1;
1627
+ const processingStart = typeof entry.processingStart === 'number' ? entry.processingStart : -1;
1628
+ if (startTime >= 0 && processingStart >= 0) {
1629
+ reportMetric(report, options.reportType, 'FID', processingStart - startTime, { unit: 'ms' });
1630
+ break;
1631
+ }
1632
+ }
1633
+ }
1634
+ catch {
1635
+ // ignore
1636
+ }
1590
1637
  });
1638
+ po.observe({ type: 'first-input', buffered: true });
1591
1639
  }
1592
1640
  catch {
1593
1641
  // ignore
1594
1642
  }
1595
1643
  }
1596
- // Resource timing:资源加载耗时(web-vitals 不包含此功能,保留原有实现)
1644
+ // Resource timing:资源加载耗时
1597
1645
  if (options.resourceTiming && typeof globalThis.PerformanceObserver === 'function') {
1598
1646
  try {
1599
1647
  const po = new PerformanceObserver((list) => {
@@ -1678,6 +1726,7 @@ function installWebPerformanceMonitor(report, opts = {}) {
1678
1726
  sampleRate: raw.sampleRate ?? 1,
1679
1727
  ignoreUrls: raw.ignoreUrls ?? [],
1680
1728
  webVitals: raw.webVitals ?? true,
1729
+ navigationTiming: raw.navigationTiming ?? true,
1681
1730
  resourceTiming: raw.resourceTiming ?? true,
1682
1731
  maxTextLength: raw.maxTextLength ?? 2000,
1683
1732
  };
@@ -2053,6 +2102,43 @@ function getBrowserDeviceInfo(options) {
2053
2102
  // ignore
2054
2103
  }
2055
2104
  }
2105
+ if (options.includeNetworkType) {
2106
+ try {
2107
+ const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
2108
+ if (conn && isPlainObject(conn)) {
2109
+ const type = conn.type;
2110
+ const eff = conn.effectiveType;
2111
+ let val = '';
2112
+ if (type === 'wifi' || type === 'ethernet') {
2113
+ val = 'WIFI';
2114
+ }
2115
+ else if (type === 'cellular' || type === 'wimax') {
2116
+ if (eff === 'slow-2g' || eff === '2g')
2117
+ val = '2G';
2118
+ else if (eff === '3g')
2119
+ val = '3G';
2120
+ else if (eff === '4g')
2121
+ val = '4G';
2122
+ else
2123
+ val = '4G';
2124
+ }
2125
+ else {
2126
+ // type 未知或不支持,降级使用 effectiveType
2127
+ if (eff === 'slow-2g' || eff === '2g')
2128
+ val = '2G';
2129
+ else if (eff === '3g')
2130
+ val = '3G';
2131
+ else if (eff === '4g')
2132
+ val = '4G';
2133
+ }
2134
+ if (val)
2135
+ out.networkType = val;
2136
+ }
2137
+ }
2138
+ catch {
2139
+ // ignore
2140
+ }
2141
+ }
2056
2142
  return out;
2057
2143
  }
2058
2144
  function createWebDeviceInfoBaseFields(opts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@be-link/cls-logger",
3
- "version": "1.0.1-beta.25",
3
+ "version": "1.0.1-beta.27",
4
4
  "description": "@be-link cls-logger - 腾讯云 CLS 日志上报封装",
5
5
  "homepage": "https://github.com/snowmountain-top/be-link",
6
6
  "author": "zhuiyi",
@@ -45,8 +45,7 @@
45
45
  ],
46
46
  "dependencies": {
47
47
  "tencentcloud-cls-sdk-js-web": "^1.0.11",
48
- "tencentcloud-cls-sdk-js-mini": "^1.0.3",
49
- "web-vitals": "^4.2.4"
48
+ "tencentcloud-cls-sdk-js-mini": "^1.0.3"
50
49
  },
51
50
  "devDependencies": {
52
51
  "rimraf": "^5.0.0",