At the moment it's hard to query for chat threads because there's no unique thread ID.

I suggest the following.

Add new indexed field thread_id to drupalchat_msg for better logs generation.
thread_id should be something like concatenation of uids (uid1 and uid2) if both are users, and 0 if it's a public chat.

After that it would be MUCH easier to build threads.

For now I've build my own module drupalchatlog as an extension to Drupal Chat, and here's some code examples from it which might be helpful.

drupalchatlog.module

<?php
/**
 * @file
 * Allows users to view chat logs.
 */

/**
 * Implements hook_permission().
 */
function drupalchatlog_permission() {
  return array(
    'access chat logs' => array(
      'title' => t('Access chat logs'),
      'description' => t('Give access to all chat logs.')
    )
  );
}

/**
 * Implements hook_menu().
 */
function drupalchatlog_menu() {
  $items = array();
  $items['user/%user/chatlogs'] = array(
    'title' => 'Chat logs',
    'page callback' => 'drupalchatlog_list',
    'page arguments' => array(1),
    'access callback' => 'drupalchatlog_access',
    'access arguments' => array(1),
    'type' => MENU_LOCAL_TASK
  );
  $items['user/%user/chatlogs/thread/%'] = array(
    'title' => 'Chat log',
    'page callback' => 'drupalchatlog_conversation',
    'page arguments' => array(1, 4),
    'access callback' => 'drupalchatlog_access',
    'access arguments' => array(1),
    'type' => MENU_CALLBACK
  );
  return $items;
}

function drupalchatlog_access($account) {
  global $user;

  if ($user->uid != $account->uid) {
    return FALSE;
  }

  return user_access('access chat logs');
}

/**
 * Implements hook_drupalchat_send().
 */
function drupalchatlog_drupalchat_send($message) {
  if ($message) {
    $thread_id = 0;
    if (is_numeric($message->uid1) && is_numeric($message->uid2)) {
      $uid1 = (int) $message->uid1;
      $uid2 = (int) $message->uid2;
      $thread_id = ($uid1 > $uid2) ? "c_{$uid2}_{$uid1}" : "c_{$uid1}_{$uid2}";
    }
    db_update('drupalchat_msg')
      ->fields(array('thread_id' => $thread_id))
      ->condition('message_id', $message->message_id)
      ->execute();
  }
}

function drupalchatlog_list($account) {
  $query = db_select('drupalchat_msg', 'c');
  $query->leftJoin('users', 'one', 'one.uid = c.uid1');
  $query->leftJoin('users', 'two', 'two.uid = c.uid2');
  $query = $query
    ->extend('PagerDefault')
    ->limit(30);
  $query->where('c.uid1 <> c.uid2');
  $query->addExpression('MAX(c.timestamp)', 'timestamp');
  $query->addExpression('COUNT(c.thread_id)', 'total');
  $query->fields('c', array('uid1', 'uid2', 'thread_id'));
  $query->fields('one', array('name'));
  $query->fields('two', array('name'));
  $query->orderBy('MAX(c.timestamp)', 'DESC');
  $query->groupBy('c.thread_id');
  $result = $query
    ->execute()
    ->fetchAll();

  $rows = array();
  foreach ($result as $data) {
    if ($data->thread_id == '0') {
      $participants = array(t('Public chat'));
    }
    else {
      $participants = array(
        ($account->uid != $data->uid1 ? l($data->name, "user/{$data->uid1}") : t('You')),
        ($account->uid != $data->uid2 ? l($data->two_name, "user/{$data->uid2}") : t('You'))
      );
    }
    $rows[] = array(
      implode('
', $participants), format_date($data->timestamp), $data->total, l(t('View'), "user/{$account->uid}/chatlogs/thread/{$data->thread_id}") ); } $build = array(); $build['table'] = array( '#theme' => 'table', '#header' => array( t('Participants'), t('Last message'), t('Total messages'), t('Operations') ), '#rows' => $rows, '#empty' => t('No chat logs available.'), ); $build['pager'] = array( '#theme' => 'pager' ); return $build; } function drupalchatlog_conversation($account, $thread_id) { $breadcrumb = array(l('Home', NULL)); $breadcrumb[] = l(t('Chat logs'), "user/{$account->uid}/chatlogs"); drupal_set_breadcrumb($breadcrumb); $uids = db_select('drupalchat_msg', 'c') ->where('c.uid1 <> c.uid2') ->condition('c.thread_id', $thread_id) ->fields('c', array('uid2', 'uid1')) ->execute() ->fetchAllKeyed(); $users = array(); $titles = array(); foreach (user_load_multiple($uids) as $user) { $variables = array( 'user_picture' => $user->picture, 'account' => $user ); $user->picture = theme('user_picture', $variables); $users[$user->uid] = $user; $titles[] = ($account->uid != $user->uid ? $user->name : t('You')); } if ($thread_id == '0') { $title = t('Public chat'); } else { $title = t('Chat log between !user1 and !user2', array('!user1' => $titles[0], '!user2' => $titles[1])); } drupal_set_title($title); $messages = db_select('drupalchat_msg', 'c') ->where('c.uid1 <> c.uid2') ->condition('c.thread_id', $thread_id) ->fields('c', array('uid1', 'message', 'timestamp')) ->orderBy('c.timestamp') ->execute() ->fetchAll(); $items = ''; foreach ($messages as $message) { $user = $users[$message->uid1]; $author = ($account->uid != $user->uid ? l($user->name, "user/{$user->uid}") : t('You')); $item = $user->picture; $item.= '
'. $author .'
'; $item.= '
'. format_date($message->timestamp) .'
'; $item.= '
'. $message->message .'
'; $items[] = $item; } $build = array(); $build['messages'] = array( '#theme' => 'item_list', '#items' => $items, '#attributes' => array( 'id' => "chat-thread-{$thread_id}", 'class' => array('chat-thread') ) ); return $build; }

drupalchatlog.install

/**
 * Implements hook_install().
 */
function drupalchatlog_install() {
  $spec = array(
    'type' => 'varchar',
    'length' => 50,
    'not null' => TRUE,
    'default' => '',
    'description' => 'Thread ID of chat message.'
  );
  db_add_field('drupalchat_msg', 'thread_id', $spec);
  db_add_index('drupalchat_msg', 'thread_id', array('thread_id'));
}

/**
 * Implements hook_uninstall().
 */
function drupalchatlog_uninstall() {
  db_drop_field('drupalchat_msg', 'thread_id');
  db_drop_index('drupalchat_msg', 'thread_id');
}