diff --git a/.gitignore b/.gitignore
index 39d0ceb6b..02c1f28a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ express/node_modules
/.pnp
.pnp.js
.vercel
+react/config-overrides.js
# testing
/coverage
diff --git a/react/src/components/Cart.jsx b/react/src/components/Cart.jsx
index fb454b71b..0dcf93fc0 100644
--- a/react/src/components/Cart.jsx
+++ b/react/src/components/Cart.jsx
@@ -4,13 +4,16 @@ import * as Sentry from '@sentry/react';
import Button from './ButtonLink';
import { connect } from 'react-redux';
import { setProducts, addProduct, removeProduct } from '../actions';
-import { getTag, itemsInCart } from '../utils/utils';
+import { countItemsInCart } from '../utils/cart';
+import { getTag } from '../utils/utils';
-function Cart({ cart, removeProduct, addProduct }) {
-
- let tags = { 'backendType': getTag('backendType'), 'cexp': getTag('cexp') }
- Sentry.metrics.increment('checkout.items_added_to_cart', itemsInCart(cart), { tags });
+function Cart({ cart, removeProduct, addProduct }) {
+ const itemsInCart = countItemsInCart(cart);
+ let tags = { 'backendType': getTag('backendType'), 'cexp': getTag('cexp'), 'items_in_cart': itemsInCart };
+ const span = Sentry.startInactiveSpan({ name: "items_added_to_cart", op: "function"});
+ span.setAttributes(tags);
+ span.end();
return (
Cart
diff --git a/react/src/components/Checkout.jsx b/react/src/components/Checkout.jsx
index d3eaa1fca..8eee4647c 100644
--- a/react/src/components/Checkout.jsx
+++ b/react/src/components/Checkout.jsx
@@ -5,7 +5,9 @@ import './checkout.css';
import * as Sentry from '@sentry/react';
import { connect } from 'react-redux';
import Loader from 'react-loader-spinner';
-import { getTag, itemsInCart } from '../utils/utils';
+import { countItemsInCart } from '../utils/cart';
+import { getTag } from '../utils/utils';
+
function Checkout({ backend, rageclick, checkout_success, cart }) {
const navigate = useNavigate();
@@ -41,11 +43,28 @@ function Checkout({ backend, rageclick, checkout_success, cart }) {
}
const [form, setForm] = useState(initialFormValues);
- let tags = { 'backendType': getTag('backendType'), 'cexp': getTag('cexp') }
+async function checkout(cart, checkout_span) {
+ console.log("Checkout called with cart:", cart);
+ console.log("Checkout span:", checkout_span);
+ const itemsInCart = countItemsInCart(cart);
+ console.log("Calculated itemsInCart:", itemsInCart);
+
+ if (!checkout_span || typeof checkout_span.setAttribute !== 'function') {
+ console.error("Invalid checkout_span object:", checkout_span);
+ return;
+ }
+
+ checkout_span.setAttribute("checkout.click", 1);
+ checkout_span.setAttribute("items_at_checkout", itemsInCart);
+
+ // Verify attributes were set
+ console.log("Span attributes after setting:", {
+ click: checkout_span.getAttribute("checkout.click"),
+ items: checkout_span.getAttribute("items_at_checkout")
+ });
- async function checkout(cart) {
- Sentry.metrics.increment('checkout.click', 1, { tags });
- Sentry.metrics.increment('checkout.items_in_cart', itemsInCart(cart), { tags });
+ let tags = { 'backendType': getTag('backendType'), 'cexp': getTag('cexp'), 'items_at_checkout': itemsInCart, 'checkout.click': 1 };
+ checkout_span.setAttributes(tags);
const stopMeasurement = measureRequestDuration('/checkout');
const response = await fetch(backend + '/checkout?v2=true', {
method: 'POST',
@@ -56,28 +75,32 @@ function Checkout({ backend, rageclick, checkout_success, cart }) {
validate_inventory: checkout_success ? "false" : "true",
}),
})
- .catch((err) => {
- Sentry.metrics.increment('checkout.error', 1, {
- tags: { status: 500 },
- });
- return { ok: false, status: 500 };
+ .catch((err) => {
+ checkout_span.setAttributes({
+ "checkout.error": 1,
+ "status": 500
})
- .then((res) => {
- stopMeasurement();
- return res;
- });
+ return { ok: false, status: 500 };
+ })
+ .then((res) => {
+ stopMeasurement();
+ return res;
+ });
if (!response.ok) {
- Sentry.metrics.increment('checkout.error', 1, {
- tags: { status: response.status, ...tags },
- });
+ checkout_span.setAttributes({
+ "checkout.error": 1,
+ "status": response.status
+ })
+
throw new Error(
[response.status, response.statusText || ' Internal Server Error'].join(
' -'
)
);
}
- Sentry.metrics.increment('checkout.success', 1, { tags });
- Sentry.metrics.distribution('checkout.order.total', cart.total);
+ checkout_span.setAttribute("checkout.success", 1)
+ checkout_span.setAttribute("checkout.order.total", cart.total);
+
return response;
}
function generateUrl(product_id) {
@@ -114,7 +137,7 @@ function Checkout({ backend, rageclick, checkout_success, cart }) {
setLoading(true);
try {
- await checkout(cart);
+ await checkout(cart, span);
} catch (error) {
Sentry.captureException(error);
hadError = true;
diff --git a/react/src/components/Products.jsx b/react/src/components/Products.jsx
index 4802e510a..63bcef655 100644
--- a/react/src/components/Products.jsx
+++ b/react/src/components/Products.jsx
@@ -85,49 +85,43 @@ function Products({ frontendSlowdown, backend, productsExtremelySlow, productsBe
related to the async keyword + babel transform, hence why it probably got
fixed with hooks (no transform on that class method anymore)"
*/
- useEffect(() => {
- // getProducts handles error responses differently, depending on the browser used
- function getProducts(frontendSlowdown) {
- [('/api', '/connect', '/organization')].forEach((endpoint) => {
- fetch(backend + endpoint, {
- method: 'GET',
- headers: { 'Content-Type': 'application/json' },
- }).catch((err) => {
- // If there's an error, it won't stop the Products http request and page from loading
- Sentry.captureException(err);
- });
+ async function getProducts(frontendSlowdown) {
+ [('/api', '/connect', '/organization')].forEach((endpoint, activeSpan) => {
+ fetch(backend + endpoint, {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' },
+ }).catch((err) => {
+ // If there's an error, it won't stop the Products http request and page from loading
+ Sentry.captureException(err);
});
-
- // When triggering a frontend-only slowdown, use the products-join endpoint
- // because it returns product data with a fast backend response.
- // Otherwise use the /products endpoint, which provides a slow backend response.
- const productsEndpoint = determineProductsEndpoint();
- const stopMeasurement = measureRequestDuration(productsEndpoint);
- fetch(backend + productsEndpoint, {
+ });
+ const productsEndpoint = determineProductsEndpoint();
+ Sentry.startSpan({ name: "Fetch Products"}, async (span) => {
+ const stopMeasurement = measureRequestDuration(productsEndpoint, span);
+ const response = await fetch(backend + productsEndpoint, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
- })
- .then((result) => {
- if (!result.ok) {
- Sentry.setContext('err', {
- status: result.status,
- statusText: result.statusText,
- });
- return Promise.reject();
- } else {
- return result.json();
- }
- })
- .then(renderProducts)
- .catch((err) => {
- return { ok: false, status: 500 };
- }).then((res) => {
- stopMeasurement()
- return res
+ });
+ const data = await response.json();
+
+ if (!response.ok) {
+ Sentry.setContext('err', {
+ status: response.status,
+ statusText: response.statusText,
});
- }
+ return;
+ }
+ renderProducts(data);
+ stopMeasurement();
+ })
+ }
- getProducts(frontendSlowdown);
+ useEffect(() => {
+ try {
+ getProducts(frontendSlowdown)
+ } catch (error) {
+ Sentry.captureException(error)
+ }
}, []);
return products.length > 0 ? (
diff --git a/react/src/utils/cart.js b/react/src/utils/cart.js
new file mode 100644
index 000000000..887748c13
--- /dev/null
+++ b/react/src/utils/cart.js
@@ -0,0 +1,16 @@
+export function countItemsInCart(cart) {
+ let totalItems = 0;
+
+ if (!cart || !cart.quantities) {
+ console.log("Cart or cart.quantities is undefined!");
+ return totalItems;
+ }
+
+ totalItems = Object.values(cart.quantities)
+ .reduce((sum, quantity) => {
+ console.log("Adding quantity:", quantity);
+ return sum + quantity;
+ }, 0);
+
+ return totalItems;
+}
\ No newline at end of file
diff --git a/react/src/utils/measureRequestDuration.js b/react/src/utils/measureRequestDuration.js
index ae17e21ab..a7d830cd2 100644
--- a/react/src/utils/measureRequestDuration.js
+++ b/react/src/utils/measureRequestDuration.js
@@ -6,16 +6,19 @@ import * as Sentry from '@sentry/react';
* @param {string} endpoint the endpoint that was called
* @returns {() => void} a function to stop the measurement
*/
-export default function measureRequestDuration(endpoint) {
+export default function measureRequestDuration(endpoint, requestSpan) {
const start = Date.now();
function stopMeasurement() {
const end = Date.now();
const duration = end - start;
- Sentry.metrics.distribution('request.duration', duration, {
- unit: 'millisecond',
- tags: { endpoint }
- });
+ if (requestSpan !== undefined) {
+ requestSpan.setAttributes({
+ "request.duration": duration,
+ "unit": "milisecond",
+ "endpoint": endpoint
+ })
+ }
}
return stopMeasurement;