import slack from "@slack/bolt";
const { App, LogLevel } = slack;

// load .env from local file
import dotenv from "dotenv";
dotenv.config();

import winston from 'winston';
import DatadogTransport from '@shelf/winston-datadog-logs-transport';

// Initialize connection to Datadog via winston library and transport
const logger = winston.createLogger({
  transports: [
    new DatadogTransport({
      apiKey: process.env.DATADOG_API_KEY, // Datadog API key
      // optional metadata which will be merged with every log message
      metadata: {
        ddsource: process.env.DATADOG_APPLICATION_NAME,
      }
    })
  ]
});

// Initialize slack app bot with bot token and signing secret
// via the slack bolt library
const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  socketMode: true, // enable the following to use socket mode
  appToken: process.env.SLACK_APP_TOKEN,
  logLevel: LogLevel.WARN
});

// -----------------
// slack message handlers

// TODO: test function. remove
app.command("/test", async ({ command, ack, say }) => {
  try {
    await ack();
    say("I'm here, gathering metrics quietly");
  } catch (error) {
    console.log("err");
    console.error(error);
  }
});


// TODO: test function. remove
app.message("hey", async ({ message, say }) => {
  try {
    const thread_ts = message.thread_ts ? message.thread_ts : message.ts;
    await say({text: `Hey yourself <@${message.user}> `, thread_ts: thread_ts });
  } catch (error) {
    console.log("err");
    console.error(error);
  }
});

// match all messages, look for content markers and generate
// log entry for datadog
app.message('', async ({ message, client, say }) => {

  try {
    console.log('Processing message', JSON.stringify(message));

    const msgText = message.text;

    function countMatches(regex) {
      let searchStr = msgText.match(regex)
      if (searchStr !== null) {
        return searchStr.length
      }
      return 0
    }

    function countSplits(regex) {
      const searchStr = msgText.split(regex)
      if (searchStr !== undefined) {
        return searchStr.length
      }
      return 0
    }

    // fetch the user info so we get their real_name
    const r1 = await client.users.info({
      user: message.user
    });
    const user = r1.user;

    // fetch the channel info so we can report channel name
    const r2 = await client.conversations.info({
      channel: message.channel
    });
    const channel = r2.channel;

    // TODO: consider whether we should filter out threaded messages
    // see: https://github.com/slackapi/bolt-js/issues/642
    // const isThreaded = (typeof message.thread_ts != undefined)
    // if (isThreaded) { }

    // log to datadog
    logger.info('message',
      {
        teamId: message.team,
        channelId: message.channel,
        channelName: channel.name,
        userId: message.user,
        userName: user.real_name,
        wordCount: countSplits(/\s+\b/),
        emojiCount: countMatches(/:[a-z_0-9]*:/g),
        offtopicCount: countMatches(/:batman:/g),
        exclaCount: countMatches(/!/g),
        questionCount: countMatches(/\?/g),
        elipsisCount: countMatches(/\.\.\./g),
        alertCount: countMatches(/<!/g),
        urlCount: countMatches(/<http/g),
        hereCount: countMatches(/\@here/),
        channelCount: countMatches(/\@channel/),
        urgentCount: countMatches(/urgent/g),
      });
  }
  catch (error) {
    console.log("err");
    console.error(error);
  }
});



(async () => {
  const port = 3000
  // Start your app
  await app.start(process.env.PORT || port);
  console.log(`⚡️ Slack Bolt app is running on port ${port}!`);
})();
@@ -1442,16 +1442,17 @@
 yourself
+,
  %3C@$%7Bmes
@@ -2635,19 +2635,16 @@
 /642%0A   
- //
  const i
@@ -2698,35 +2698,9 @@
 ned)
-%0A    // if (isThreaded) %7B %7D
+;
 %0A%0A  
@@ -2915,24 +2915,54 @@
 .real_name,%0A
+        isThread: isThreaded,%0A
         word

Include isThreaded flag in logs