or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

http-client.mdindex.mdlogger.mdmappers.mdrepository-management.mdstate-management.mdtypes-extraction.mdtypes-loading.mdworker-management.md
tile.json

logger.mddocs/

Logger Utilities

Logging utilities in the Airdrop SDK provide context-aware logging and error serialization for better observability during extraction and loading operations.

Capabilities

Serialize Axios Error

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' },
    });
  },
});

Format Axios Error (Deprecated)

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;

Get Printable State

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' },
    });
  },
});

Common Patterns

Error Logging with Serialization

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;
  }
}

State Logging for Debugging

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' },
    });
  },
});

Comprehensive Error Handling

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' },
    });
  },
});

Retry Logic with Logging

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;
}

Progress Logging

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' },
    });
  },
});

Best Practices

Always Serialize Axios Errors

try {
  await axiosClient.get(url);
} catch (error) {
  if (error.isAxiosError) {
    const serialized = serializeAxiosError(error);
    console.error('Request failed:', serialized);
  }
  throw error;
}

Use Printable State for Large Objects

// 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 summarized

Log at Key Points

processTask({
  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' },
    });
  },
});

Include Context in Error Messages

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);
  }
}