# Nodejs logging using winston

**URL:** <https://community.grafana.com/t/nodejs-logging-using-winston/76990>\
**Category:** Developers & API\
**Tags:** api, nodejs\
**Created:** [November 29, 2022, 3:31pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990 "2022-11-29T15:31:39Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![terchris](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/terchris/32/28024_2.png) [@terchris](https://community.grafana.com/u/terchris)\
**Post date:** [November 29, 2022, 3:31pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/1 "2022-11-29T15:31:39Z")

</div>

How to log from my node application using winston ?  
I can find one article about it. But that howto requires patching to make it work,

> **[How to configure Grafana Loki to collect Node.js logs](https://grafana.com/blog/2022/07/07/how-to-configure-grafana-loki-with-a-node.js-e-commerce-app/)**
>
> To better understand the customer experience for my dad's online honey business, I introduced logging capabilities to the Node.js app with Grafana Loki.

Sending a log from an application must be pretty basic. But I can’t find any examples.  
I hope someone has a simple example of getting a log from an application running in nodejs.  
A simple “Hello world” 🙂

---

<div class="post-metadata">

**Author:** ![yosiasz](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/yosiasz/32/45847_2.png) [@yosiasz](https://community.grafana.com/u/yosiasz)\
**Post date:** [November 29, 2022, 6:53pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/2 "2022-11-29T18:53:27Z")

</div>

Welcome

In your nodejs app just pop this in for starters

```auto
const { createLogger, transports, format } = require("winston");
const LokiTransport = require("winston-loki");

const l_log = createLogger({
    transports: [new LokiTransport({
        host: "http://127.0.0.1:3100",
        labels: { app: 'honeyshop'},
        json: true,
        format: format.json(),
        replaceTimestamp: true,
        onConnectionError: (err) => console.error(err)
      }),
      new transports.Console({
        format: format.combine(format.simple(), format.colorize())
      })]
  })

  l_log.info({ message: `Hello World`, labels: { 'origin': 'api' } })

```

 ![image](https://us1.discourse-cdn.com/grafana/original/3X/8/0/805e5698dd5bea9c3f420bc55addb1c11bc17eac.png)

---

<div class="post-metadata">

**Author:** ![terchris](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/terchris/32/28024_2.png) [@terchris](https://community.grafana.com/u/terchris)\
**Post date:** [November 30, 2022, 8:39am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/3 "2022-11-30T08:39:29Z")

</div>

Hi @yosiasz and thank you for your reply.

In your example, the host is on the same machine as the node app is running.  
I would prefer not to set up grafana system myself. Rather use the Grafana Cloud Free account ( [Grafana Cloud | Observability platform overview](https://grafana.com/products/cloud/) ).

As [Dan Mihai Dinu](https://grafana.com/author/dan_dinu/) writes in his post - winston-loki does not work when sending logs to the hosted grafana service.

> Bummer, it doesn’t work. After a good hour of debugging, I noticed that _winston-loki_ works fine with local instances of Grafana Loki, but it doesn’t authenticate properly to send requests to Grafana Cloud Logs

From the screenshot in his article, I see that the version he is patching is winston-loki 6.0.5.  
The latest version is now 6.0.6 and I don’t know if the problem is fixed or not. And I’m not sure if his patch for version 6.0.5 will work on 6.0.6.

To me, this seems like a bug. But I’m not sure whether it is in Grafana cloud or winston-loki.

---

<div class="post-metadata">

**Author:** ![yosiasz](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/yosiasz/32/45847_2.png) [@yosiasz](https://community.grafana.com/u/yosiasz)\
**Post date:** [November 30, 2022, 8:45am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/4 "2022-11-30T08:45:09Z")

</div>

> [@terchris](#):
>
> In your example, the host is on the same machine as the node app is running.

Hey,

You are correct @terchris . Bummer indeed. I think you are going to be the one to lead us where no person has gone before 😉

So the main question is why would it not work when it is a remote host?  
Also can one bypass winston-loki and hit loki using it’s own api?

> **[Grafana Loki HTTP API | Grafana Loki documentation](https://grafana.com/docs/loki/latest/reference/api/)**
>
> Loki exposes REST endpoints for operating on a Loki cluster. This section details the REST endpoints.

And check out how other languages do it and grok it in javascript

> <https://github.com/sleleko/devops-kb/blob/master/python/push-to-loki.py>

Thinking out loud

---

<div class="post-metadata">

**Author:** ![terchris](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/terchris/32/28024_2.png) [@terchris](https://community.grafana.com/u/terchris)\
**Post date:** [November 30, 2022, 9:00am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/5 "2022-11-30T09:00:11Z")

</div>

Hi  
Based on the article by Dan Mihai Dinu I have tested sending data to grafana cloud using postman.

 ![Screen Shot 2022-11-30 at 09.48.32](https://us1.discourse-cdn.com/grafana/original/3X/4/d/4d58d4a249165809c7242efa5ed40dee275c8330.png)  
It works just fine. There is a undocumented part in his article. That is the first parameter in values. In my example, when I tested yesterday, I set it to “1669731652002000001”,  
It is the UNIX timestamp ( [https://www.unixtimestamp.com/](https://www.unixtimestamp.com/))

Also note that the URL contains the userid and password. Mine looks like this:  
[https://333666:eyJrIjoiMDc5.......@logs-prod-eu-west-0.grafana.net/loki/api/v1/push](https://333666:eyJrIjoiMDc5.......@logs-prod-eu-west-0.grafana.net/loki/api/v1/push)

This is the body of my message:

```auto
{
  "streams": [
    {
      "stream": {
        "level": "info",
        "app": "urbalurba"
      },
      "values": [
        [
             "1669731652002000001",
          "{\"timestamp\":\"2022-11-15T12:08:57.322Z\",\"logMessage\":\"Updated merge\",\"jobname\":\"webpage_info2merge\",\"idName\":\"bamble.kommune.no\",\"counter\":null,\"totalCount\":null,\"level\":\"info\",\"message\":\"Updated merge\"}"
        ]
      ]
    }
  ]
}

```

---

<div class="post-metadata">

**Author:** ![yosiasz](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/yosiasz/32/45847_2.png) [@yosiasz](https://community.grafana.com/u/yosiasz)\
**Post date:** [November 30, 2022, 9:30am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/6 "2022-11-30T09:30:53Z")

</div>

Cool. Not sure what you are trying to point out in your last post. Anyways I would Implement what worked in postman in the code for nodejs

Meaning a POST also adding user name and token in the url

Or I believe createLogger has one option for that: basicAuth

---

<div class="post-metadata">

**Author:** ![terchris](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/terchris/32/28024_2.png) [@terchris](https://community.grafana.com/u/terchris)\
**Post date:** [November 30, 2022, 9:52am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/7 "2022-11-30T09:52:26Z")

</div>

Hi  
In my previous post I was just pointing out that it is possible to send log directly to grafana cloud using the API.

I could implement my own function to just send my log directly to grafana cloud using that API. Then there would be no need for winston-loki at all.  
But I’m sure that the internal workings of winston-loki is more complex than just a wrapper to that API. So it is better to solve the problem in the winston-loki.

I do not have the skills to fix the winston-loki ☹

---

<div class="post-metadata">

**Author:** ![yosiasz](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/yosiasz/32/45847_2.png) [@yosiasz](https://community.grafana.com/u/yosiasz)\
**Post date:** [November 30, 2022, 9:58am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/8 "2022-11-30T09:58:16Z")

</div>

> [@terchris](#):
>
> But I’m sure that the internal workings of winston-loki is more complex than just a wrapper to that API

Are you 100% sure? 😉

Check this out

```auto
logger.add(new LokiTransport({
  host: 'http://127.0.0.1:3100',
  json: true,
  basicAuth: 'username:password',
  labels: { job: 'winston-loki-example' }
}))

```

---

<div class="post-metadata">

**Author:** ![yosiasz](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/yosiasz/32/45847_2.png) [@yosiasz](https://community.grafana.com/u/yosiasz)\
**Post date:** [November 30, 2022, 7:00pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/9 "2022-11-30T19:00:22Z")

</div>

So I spun up a cloud loki

![image](https://us1.discourse-cdn.com/grafana/original/3X/a/5/a5266d38ef03bdc3cd03ba70162f14c0c26d991a.png)

then using the basicAuth setting I used the user and password as follows

```auto
transports: [new LokiTransport({
        host: "https://your_cloud_url_from_above",
        labels: { app: 'kumbamboom'},
        json: true,
        basicAuth: 'user_from_above:password_from_above',
        format: format.json(),
        replaceTimestamp: true,

```

---

<div class="post-metadata">

**Author:** ![terchris](https://sea2.discourse-cdn.com/grafana/user_avatar/community.grafana.com/terchris/32/28024_2.png) [@terchris](https://community.grafana.com/u/terchris)\
**Post date:** [December 2, 2022, 12:49pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/10 "2022-12-02T12:49:22Z")

</div>

Thanks @yosiasz  
Based on your input and [Winston-loki not working with Grafana Cloud Loki · Issue #108 · JaniAnttonen/winston-loki · GitHub](https://github.com/JaniAnttonen/winston-loki/issues/108) I created this simple code. I think that my problem was that I had my parameters wrong (URL and probably password). There are probably return codes that can be inspected to help in case it does not work. I was looking for a simple code to test- I could not find one so I created it.

```nohighlight

/* The siplest test ever to see if grafana cloud and winston is working 
A small node app that sends a log message to Grafana Cloud Loki using the winston-loki transport.
To you by terchris and friends.
*/
import winston from "winston";
import LokiTransport from "winston-loki"

// https://grafana.com/orgs/urbalurba (change urbalurba to your own org)
// in the Loki card. Click on the Details button. On the next page you will se the Grafana Data Source settings.
// Create a password and replace the const variables below with your own values. 
const GRAFANA_HOST = "https://logs-prod-eu-west-0.grafana.net";
const MY_APP_NAME = "urbalurba";

const GRAFANA_USERID = "333666";
const GRAFANA_PASSWORD = "eyJr1234567890FjYzZlOTg2NTE5ZDIyY12345678900ODdlZjAx1234567890IsIm4iOiJ1234567890iwi1234567890cyM30=";

// start leave this as is
const GRAFANA_BASICAUTH = GRAFANA_USERID + ":" + GRAFANA_PASSWORD;
const logger = winston.createLogger({

    level: 'debug',
      
    transports: [
      new LokiTransport({
        host: GRAFANA_HOST,
          labels: { app: MY_APP_NAME },
          json: true,
          basicAuth: GRAFANA_BASICAUTH,
          format: winston.format.json(),
          replaceTimestamp: true,
          onConnectionError: (err) => console.error(err)
        }),
      new winston.transports.Console({}),      
    ],
  });
// end leave this as is  

// send some log messages
logger.info("Starting test");
logger.debug("sending debug message");
logger.warn("sending warn message");
logger.error("sending error message");
logger.info("done testing");

// To see the logging in grafana cloud, go to Explore https://urbalurba.grafana.net/explore (change urbalurba to your own org)
// At the top there is a dropdown. Select the one with the Loki logo (in my case grafanacloud-urbalurba-logs) 
// In the "Select label" dropdown select "app" and in the "Select value" dropdown select "urbalurba" (change urbalurba to your own app name)
// Click on the "Run Query" button in the upper right corner. You should see the log messages you sent above.

```

---

<div class="post-metadata">

**Author:** ![architectinprogress](https://avatars.discourse-cdn.com/v4/letter/a/f9ae1b/32.png) [@architectinprogress](https://community.grafana.com/u/architectinprogress)\
**Post date:** [December 29, 2022, 8:43am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/11 "2022-12-29T08:43:33Z")

</div>

@terchris Hey there.  
I tried hitting the url using postman. I’m getting a 204 response and the labels are also getting created in Loki but the logs shows “No logs found” What am I missing? TIA

---

<div class="post-metadata">

**Author:** ![architectinprogress](https://avatars.discourse-cdn.com/v4/letter/a/f9ae1b/32.png) [@architectinprogress](https://community.grafana.com/u/architectinprogress)\
**Post date:** [December 29, 2022, 4:31pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/12 "2022-12-29T16:31:57Z")

</div>

**Update** : The logs for the post request that I made yesterday is showing up now. But its not showing for the recent requests. I guess there is a lag. Any help will be appreciated.

---

<div class="post-metadata">

**Author:** ![arielb](https://avatars.discourse-cdn.com/v4/letter/a/839c29/32.png) [@arielb](https://community.grafana.com/u/arielb)\
**Post date:** [August 20, 2023, 2:16pm UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/13 "2023-08-20T14:16:19Z")

</div>

@architectinprogress I was facing the same issue, look at the timestamp in nanoseconds that you send and see that the endpoint matches the one needed for Loki!  
**Note:** by default, Grafana only looks 6h ago.  
`POST` `https://<username>:<api_key>@<subdomain>.grafana.net/loki/api/v1/push`

```json
{
  "streams": [
    {
      "stream": {
        "level": "info",
        "app": "bees"
      },
      "values": [
        [
          "1692536838000000000",
          "{\"level\":\"info\",\"message\":\"Hello bananas!\"}"
        ]
      ]
    }
  ]
}

```

---

<div class="post-metadata">

**Author:** ![mvogelenzang](https://avatars.discourse-cdn.com/v4/letter/m/e9a140/32.png) [@mvogelenzang](https://community.grafana.com/u/mvogelenzang)\
**Post date:** [November 13, 2024, 5:57am UTC](https://community.grafana.com/t/nodejs-logging-using-winston/76990/14 "2024-11-13T05:57:55Z")

</div>

If anyone needs an on the fly patch for winston-loki, this worked for me:

```auto
import winston from 'winston';
import LokiTransport from 'winston-loki';
import dotenv from 'dotenv';
import fetch from 'node-fetch';

dotenv.config(); // Load environment variables

// Extend LokiTransport
class ExtendedLokiTransport extends LokiTransport {
    constructor(options) {
        // Pass options to the base constructor
        super(options);

        // Ensure options are stored
        this.options = options;
    }

    log(info, callback) {
        const { message, ...metadata } = info;

        // Prepare the log entry
        const logEntry = {
            message,
            ...metadata
        };

        // Remove the `level` field from metadata
        delete metadata.level;

        // Prepare the payload
        const payload = {
            streams: [
                {
                    stream: this.options.labels || {}, // Ensure labels are provided
                    values: [[`${Date.now()}000000`, JSON.stringify(logEntry)]],
                },
            ],
        };

        // Prepare headers
        const headers = {
            'Content-Type': 'application/json',
            Authorization: `Basic ${Buffer.from(this.options.basicAuth).toString('base64')}`,
        };

        // Send the payload to Loki
        fetch(this.options.host, {
            method: 'POST',
            headers,
            body: JSON.stringify(payload),
        })
            .then((response) => {
                if (!response.ok) {
                    console.error(`Loki transport error (${response.status}): ${response.statusText}`);
                } else {
                    console.log('Log successfully sent to Loki');
                }
                callback();
            })
            .catch((err) => {
                console.error('Loki transport fetch error:', err);
                callback(err);
            });
    }
}

// Create the logger using the extended transport
export const logger = winston.createLogger({
    level: 'info',
    format: winston.format.json(),
    transports: [
        new ExtendedLokiTransport({
            host: process.env.LOKI_URL,
            basicAuth: `${process.env.LOKI_USERNAME}:${process.env.LOKI_PASSWORD}`,
            labels: { app: 'exactplay-unified-api-server' },
        }),
    ],
});

```
