Logging utilities in the Airdrop SDK provide context-aware logging and error serialization for better observability during extraction and loading operations.
Serializes Axios errors into a structured format with HTTP request/response details.
/**
* Serializes an Axios error into a structured format
* Extracts method, URL, parameters, status code, headers, and data
* Includes CORS/network failure indicator when no response is available
* @param error - Axios error to serialize
* @returns Structured object with error details
*/
function serializeAxiosError(error: AxiosError): AxiosErrorResponse;
interface AxiosErrorResponse {
config: {
method?: string;
params?: any;
url?: string;
};
isAxiosError: boolean;
isCorsOrNoNetworkError: boolean;
response?: {
data: any;
headers: RawAxiosResponseHeaders;
status: number;
statusText: string;
};
code?: string;
message?: string;
}Usage Examples:
import { axiosClient, serializeAxiosError } from '@devrev/ts-adaas';
import { processTask, ExtractorEventType } from '@devrev/ts-adaas';
processTask({
task: async ({ adapter }) => {
try {
const response = await axiosClient.get('https://api.example.com/data');
await processData(response.data);
await adapter.emit(ExtractorEventType.ExtractionDataDone);
} catch (error) {
if (error.isAxiosError) {
// Serialize Axios error for logging
const serialized = serializeAxiosError(error);
console.error('HTTP request failed:', serialized);
// Use serialized error information
if (serialized.response) {
console.error('Status:', serialized.response.status);
console.error('Response:', serialized.response.data);
} else {
console.error('Network error:', serialized.message);
}
}
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: error.message },
});
}
},
onTimeout: async ({ adapter }) => {
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});Formats an Axios error to a printable format. This function is deprecated; use serializeAxiosError instead.
/**
* Formats an Axios error to a printable format
* @param error - Axios error to format
* @returns Formatted error object
* @deprecated Use serializeAxiosError instead
*/
function formatAxiosError(error: AxiosError): object;Converts a state object into a printable format where arrays are summarized.
/**
* Converts a state object into a printable format
* Arrays show their length, first item, and last item instead of all elements
* Objects are recursively processed and primitives are returned as-is
* @param state - State object to convert
* @returns Printable representation with summarized arrays
*/
function getPrintableState(state: Record<string, any>): PrintableState;
type PrintableState = Record<string, any>;
interface PrintableArray {
type: 'array';
length: number;
firstItem?: any;
lastItem?: any;
}Usage Examples:
import { getPrintableState } from '@devrev/ts-adaas';
processTask({
task: async ({ adapter }) => {
const state = adapter.state;
// Log state with summarized arrays
const printableState = getPrintableState(state);
console.log('Current state:', printableState);
// If state has large arrays, they'll be summarized
// Example state:
// {
// processedIds: [1000 items],
// users: { completed: true }
// }
// Printable output:
// {
// processedIds: { type: 'array', length: 1000, firstItem: 'id-1', lastItem: 'id-1000' },
// users: { completed: true }
// }
await adapter.emit(ExtractorEventType.ExtractionDataDone);
},
onTimeout: async ({ adapter }) => {
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});import { axiosClient, serializeAxiosError } from '@devrev/ts-adaas';
async function fetchData(url: string) {
try {
const response = await axiosClient.get(url);
return response.data;
} catch (error) {
if (error.isAxiosError) {
const serialized = serializeAxiosError(error);
// Log structured error
console.error('Request failed:', {
url: serialized.config.url,
method: serialized.config.method,
status: serialized.response?.status,
statusText: serialized.response?.statusText,
isNetworkError: serialized.isCorsOrNoNetworkError,
});
// Check specific error conditions
if (serialized.response?.status === 404) {
console.warn('Resource not found');
} else if (serialized.isCorsOrNoNetworkError) {
console.error('Network connectivity issue');
}
}
throw error;
}
}import { getPrintableState } from '@devrev/ts-adaas';
processTask({
task: async ({ adapter }) => {
// Log initial state
console.log('Initial state:', getPrintableState(adapter.state));
// Process data
await processPhase1();
// Log state after phase 1
adapter.state = {
...adapter.state,
phase1Complete: true,
};
console.log('State after phase 1:', getPrintableState(adapter.state));
// Process data
await processPhase2();
// Log final state
adapter.state = {
...adapter.state,
phase2Complete: true,
};
console.log('Final state:', getPrintableState(adapter.state));
await adapter.emit(ExtractorEventType.ExtractionDataDone);
},
onTimeout: async ({ adapter }) => {
// Log state at timeout
console.log('State at timeout:', getPrintableState(adapter.state));
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});import { axiosClient, serializeAxiosError } from '@devrev/ts-adaas';
import { processTask, ExtractorEventType } from '@devrev/ts-adaas';
processTask({
task: async ({ adapter }) => {
try {
const response = await axiosClient.get('https://api.example.com/data');
if (!response.data || !Array.isArray(response.data.items)) {
throw new Error('Invalid response format');
}
await processItems(response.data.items);
await adapter.emit(ExtractorEventType.ExtractionDataDone);
} catch (error) {
let errorMessage = 'Unknown error';
if (error.isAxiosError) {
const serialized = serializeAxiosError(error);
if (serialized.response) {
// Server error
errorMessage = `HTTP ${serialized.response.status}: ${serialized.response.statusText}`;
console.error('Server error:', {
status: serialized.response.status,
data: serialized.response.data,
url: serialized.config.url,
});
} else if (serialized.isCorsOrNoNetworkError) {
// Network error
errorMessage = `Network error: ${serialized.message}`;
console.error('Network error:', serialized.code, serialized.message);
}
} else if (error instanceof Error) {
// Application error
errorMessage = error.message;
console.error('Application error:', error);
}
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: errorMessage },
});
}
},
onTimeout: async ({ adapter }) => {
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});import { axiosClient, serializeAxiosError } from '@devrev/ts-adaas';
async function fetchWithRetry(url: string, maxRetries: number = 3): Promise<any> {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempt ${attempt} of ${maxRetries}`);
const response = await axiosClient.get(url);
return response.data;
} catch (error) {
lastError = error;
if (error.isAxiosError) {
const serialized = serializeAxiosError(error);
console.warn(`Attempt ${attempt} failed:`, {
status: serialized.response?.status,
isNetworkError: serialized.isCorsOrNoNetworkError,
});
// Don't retry on 4xx client errors
if (serialized.response && serialized.response.status >= 400 && serialized.response.status < 500) {
console.error('Client error, not retrying');
throw error;
}
}
// Wait before next retry
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Waiting ${delay}ms before retry`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
throw lastError;
}import { getPrintableState } from '@devrev/ts-adaas';
processTask({
task: async ({ adapter }) => {
const totalPages = 10;
for (let page = 1; page <= totalPages; page++) {
console.log(`Processing page ${page} of ${totalPages}`);
const data = await fetchPage(page);
await processPage(data);
// Update and log state
adapter.state = {
...adapter.state,
currentPage: page,
processedCount: (adapter.state.processedCount || 0) + data.length,
};
console.log('Progress:', getPrintableState({
page: `${page}/${totalPages}`,
itemsProcessed: adapter.state.processedCount,
}));
}
await adapter.emit(ExtractorEventType.ExtractionDataDone);
},
onTimeout: async ({ adapter }) => {
console.log('Timeout occurred at state:', getPrintableState(adapter.state));
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});try {
await axiosClient.get(url);
} catch (error) {
if (error.isAxiosError) {
const serialized = serializeAxiosError(error);
console.error('Request failed:', serialized);
}
throw error;
}// Don't do this with large state
console.log('State:', JSON.stringify(adapter.state)); // Can be very large
// Do this instead
console.log('State:', getPrintableState(adapter.state)); // Arrays summarizedprocessTask({
task: async ({ adapter }) => {
console.log('Starting extraction');
// Log before major operations
console.log('Fetching users...');
const users = await fetchUsers();
console.log(`Fetched ${users.length} users`);
console.log('Fetching tasks...');
const tasks = await fetchTasks();
console.log(`Fetched ${tasks.length} tasks`);
// Log state changes
console.log('Final state:', getPrintableState(adapter.state));
await adapter.emit(ExtractorEventType.ExtractionDataDone);
},
onTimeout: async ({ adapter }) => {
console.log('Timeout - state:', getPrintableState(adapter.state));
await adapter.emit(ExtractorEventType.ExtractionDataError, {
error: { message: 'Timeout' },
});
},
});try {
await processItem(item);
} catch (error) {
if (error.isAxiosError) {
const serialized = serializeAxiosError(error);
console.error(`Failed to process item ${item.id}:`, {
itemId: item.id,
error: serialized,
});
} else {
console.error(`Failed to process item ${item.id}:`, error);
}
}