สร้าง Logging เทพๆ ด้วย Winston ใน Node.js

NottDev
4 min readSep 28, 2019

--

วันนี้เราจะมาพูดถึง “Winston” ซึ่งเค้าคือผู้ชนะรางวัลโนเบลและผู้ได้รับเลือกให้เป็นนายกรัฐมนตรีของอังกฤษ 2 ครั้ง เด่วๆ!!! นั้นมัน “Winston Churchill” แต่ Winston ที่เราจะมาพูดถึงวันนี้เป็น library มากความสามารถสำหรับ logging ใน node.js โดย Winston นั้นสามารถนำไปใช้ได้หลายบริบท รวมถึงใน Node web frameworks อย่าง Express และ Node CLI apps ซึ่งเราจะมาพูดถึง feature ที่เหมาะสมสำหรับการนำไปใช้งานกับ IoT เช่น การบันทึกรายการ(logging)การทำงานต่างๆ ตามเวลาที่เข้ามาลงในไฟล์ (เวอร์ชั่นปัจจุบันขณะเขียนบทความนี้ winston v. 3.2.1)

ข้อหัวทั้งหมดที่จะพูดในบทความนี้

  • Getting started with Winston
  • Winston logging levels
  • Colorize Winston console log output
  • Add timestamps to the log entries
  • Log to a file in addition to the console
  • Log to console in standard text format and log to file in JSON format
  • Log to a file that rotates daily
  • Bonus — Add custom text to log entries for name of file calling Winston logger
  • Conclusion

Getting started with Winston

เริ่มจากการสร้างโฟลเดอร์โปรเจคกันก่อนนะครับ ในที่นี้ใช้ชื่อว่า “winston-test”

$ mkdir winston-test && cd winston-test

สร้างไฟล์ package.js ขึ้นมาด้วยคำสั่งนี้

$ yarn init -y

ตามมาด้วยการติดตั้งพระเอกของเราครับ ด้วยคำสั่งต่อไปนี้

$ yarn add winston

สร้างไฟล์ index.js ขึ้นมาแล้วใช้โค้ดต่อไปนี้

เริ่มจากการ import/require module ของ winston และเลือกใช้ 3 ฟังก์ชัน

  • createLogger => สำหรับสร้างตัว logger ขึ้นมาเรียกใช้
  • format => สำหรับกำหนดรูปแบบของ output เช่น text , json
  • transports =>สำหรับกำหนดช่องทางของ output เช่น console, file

จากนั้นลองรันโปรแกรมด้วยคำสั่งต่อไปนี้

$ node index.js

ควรจะเห็นผลลัพธ์ตามนี้

หรืออาจจะลองเปลี่ยน format ของ output ให้เป็น json สามารถ comment โค้ดส่วนที่เป็น format: format.simple() และเปิดที่เป็น format: format.json()

// format: format.simple(),
format: format.json(),

จากนั้นลองรันโปรแกรมอีกครั้ง ควรจะเห็นผลลัพธ์ตามนี้

Winston logging levels

หากต้องการดูละเอียดแบบเต็มๆสามารถดูได้ที่ Document สำหรับ winston นั้นจะมีระดับของ logging ให้ใช้หลายระดับ จากโค้ดตัวอย่างด้านบนนั้น เราใช้แค่ “info” กับ “debug” โดยค่าเริ่มต้น Winston ใช้ระดับ logging ที่ใช้งานโดย npm (โดยค่าน้อยสุดจะมีสำคัญสูงสุด ส่วนค่าสูงสุดจะมีความสำคัญน้อยสุด)

{ error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }

ประโชยน์ของระดับของ logging คือเราสามารถนำมาใช้ในการพิจารณาเลือกว่าต้องการแสดง output ออกมาให้เห็นอย่างไร เพื่อให้ง่ายต่อการนำมาใช้หาข้อผิดพลาดและแก้ไขปัญหาที่เกิดขึ้นกับโปรแกรมได้

จากโค้ดตัวอย่างก่อนหน้า ให้เพิ่ม logging ระดับ silly ตามโค้ดด้านล่าง

จากนั้นลองรันโปรแกรม ซึ่งจะพบว่า ไม่ปรากฏ output จาก logger.silly @_@

เนื่องจากเราได้กำหนด level property ในฟังก์ชัน createLogger เป็น “debug” ซึ่งหมายถึงเราจะสามารถใช้งานระดับที่เท่ากันและสูงกว่าได้เท่านั้น คือ error, warn, info, verbose และ debug ดังนั้นให้เราเปลี่ยน level property เป็น “silly” ตามโค้ดด้านล่าง

แล้วลองรันโปรแกรมอีกครั้ง เย้!!! logging message แสดงออกมาให้เห็นแล้ว >_<

Winston ยังมีระดับของ logging อื่นให้ใช้ เช่น ระดับของ syslog และยังสามารถให้สร้างระดับ(lavel) ของเราเองได้ โครตแจ่ม!!!

Colorize Winston console log output

จะดีกว่าไหมถ้าเราสามารถเพิ่มแต่งสีสรรลงใน logging message ได้ ซึ่งน่าจะทำให้เราดู log ได้ง่ายขึ้นมาก Winston ก็เตรียมไว้ให้แล้ว เหลือแค่ให้เราเรียกใช้งานเท่านั้น โดยเพิ่ม format.colorize() ตามโค้ดด้านล่าง

เนื่องจากเราสามารถกำหนดค่าให้ format property ในฟังก์ชัน createLogger ได้หลายค่า ดังนั้นเราจึงต้องกำหนดค่าต่างๆในฟังก์ชัน format.combine(.. , .., …)

Add timestamps to the log entries

การเพิ่ม timestamp ให้แต่ log เมื่อมีการเรียกเข้ามา ทำให้ทราบถึง วันและเวลา ของแต่ละเหตุการณ์ ซึ่งมีประโยชน์มากสำหรับ IoT Application และรวมถึง application อื่นๆ ที่ให้ความสำคัญกับเรื่องนี้ สิ่งที่เราต้องเพิ่มในโค้ดมีอะไรบ้างมาดูกันเลย

จากโค้ดด้านบนเราจะเห็น 2 ฟังก์ชันที่เพิ่มเข้ามาใหม่ คือ

  • format.timestamp() => สำหรับกำหนดรูปแบบของ วันและเวลา (datetime format)
  • format.printf() => สำหรับกำหนดรูปแบบของ output message

ผลลัพธ์ที่ได้

Log to a file in addition to the console

หากเราต้อง log ลงในไฟล์ด้วยนอกเหนือจากใน console เราสามารถทำได้ตามนี้เลย

จากตัวอย่างโค้ดด้านบน เราจะทำการสร้างโฟลเดอร์ log ถ้ายังไม่มี และเราได้ทำการเพิ่มช่องทางของ output ด้วย transports property ในฟังก์ชัน createLogger โดยได้กำหนดเกณฑ์ของระดับ logging ที่ต่างกัน หากรันโปรแกรมด้วย development environment เราจะใช้ระดับของ logging เป็น “debug” ซึ่งจะทำให้ logging message ในไฟล์มากกว่าใน console เนื่องจากใน console ใช้ระดับของ logging เป็น “info” นั้นเอง

เมื่อเรารันโปรแกรม ให้สังเกตุในโฟลเดอร์โปรเจค จะมีการสร้างโฟลเดอร์ชื่อ log ขึ้นมา และมีไฟล์ชื่อ results.log ปรากฎอยู่

ผลลัพธ์จาก console

ผลลัพธ์จากไฟล์ log

Log to console in standard text format and log to file in JSON format

หากต้องการ log ลงใน console ในรูปแบบของ Standard Text Format และลงในไฟล์ เป็นรูปแบบของ json ก็สามารถทำได้ตามโค้ดด้านล่างเลย

ในกรณีนี้ สามารถทำได้โดยการเปลี่ยนค่า Global ของการกำหนดรูปแบบของ output ใน format property ในฟังก์ชัน createLogger เป็น format.json() ตามตัวอย่างโค้ดด้านบน

ผลลัพธ์จาก console

ผลลัพธ์จากไฟล์ log

Log to a file that rotates daily

สำหรับตัวอย่างสุดท้าย เราจะทำการเพิ่ม module สำหรับการสร้างไฟล์ log แบบอัตโนมัติทุกวัน (Dialy) การทำงานแบบเดียวกันนี้ สามารถทำได้หลายวิธีรวมถึงการใช้คำสั่ง logrotate ในโลกของ Linux ด้วย แต่อย่างไรก็ตาม เราจะมาสาธิตวิธีทำด้วย Winston กัน

เริ่มจากการติดตั้ง module เพิ่มในโปรเจค ด้วยคำสั่งต่อไปนี้

$ yarn add winston-daily-rotate-file

หลังจากที่ติดตั้งเรียบร้อย เราก็พร้อมที่จะเขียนโค้ดกันแล้ว ลุยโล๊ดดด++

ในโค้ดตัวอย่างด้านบน เราได้ทำการเปลี่ยนรูปแบบของช่องทาง output ด้วยไฟล์ (file transport) มาเป็นแบบ winston-daily-rotate-file ที่เราได้ทำการติดตั้งจากขั้นตอนก่อนหน้านี้ ซึ่งเมื่อเราใช้ dailyRotateFileTransport เรายังสามารถใช้การกำหนดคุณสมบัติต่างๆเดิมได้อีกด้วย เช่น รูปแบบของ output message และที่อยู่ของไฟล์ log มันเป็นอะไรที่ดีงามพระรามแปดจริงๆ

จากตัวอย่างข้างต้น ถ้าสังเกตุดีๆจะเห็นว่าในไฟล์ log ที่ได้จะมีรูปแบบของระดับ logging หลากหลายขึ้น เนื่องจากเราได้เปลี่ยนระดับของ logging เป็น “verbose” ถ้าโปรแกรมใน development environment ซึ่งคุณสามารถไปทดลองเปลี่ยนระดับของ logging แล้วสังเกตุการแสดงของ logging message ว่าแบบไหนแสดงหรือไม่แสดง ใน console และไฟล์ log เพื่อเพิ่มความเข้าสำหรับการใช้งาน winstom ให้มากยิ่งขึ้น

สามารถดูตัวอย่างการใช้งานเพิ่มเติมได้ที่ example directory บน Winston GitHub

Bonus — Add custom text to log entries for name of file calling Winston logger

มีโบนัสให้ด้วยครับ หากต้องการแสดงชื่อไฟล์ที่เรียกใช้ logger ด้วย สามารถทำได้ตามโค้ดด้านล่าง

จากโค้ดตัวอย่างด้านบน ได้ทำการเพิ่มค่าใน format property ในฟังก์ชัน createLogger เพิ่ม format.label() เข้ามา

format.label({ label: path.basename(process.mainModule.filename) }),

จากนั้นเพิ่ม ${info.label} ในตำแหน่งที่ต้องการให้แสดงผลใน message format

format.printf(  

info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`
)

ผลลัพธ์จาก console

ผลลัพธ์จากไฟล์ log

Conclusion

ในบทความนี้เราได้แนะนำการใช้งาน feature เพียงเล็กน้อยจาก feature ทั้งหมดของ Winston ซึ่งหวังเป็นอย่างยิ่งว่าท่านที่เข้ามาอ่านจะได้รับความรู้และความเข้าใจเพิ่มมากขึ้น เกี่ยวกับการสร้าง logging บน Node.js ด้วย Winston ก่อนจากกัน ถ้าชอบบทความนี้ก็อย่างลืมกด Like กด Subscribe และกด Shareให้กับบทความนี้ด้วย จะเป็นกำลังใจให้กับคนเขียนมากเลยครับ ขอบคุณครับ ^_^

Reference:

(ข้อมูลอาจมีข้อผิดพลาด ถ้าจะเอาบทความนี้ไปอ้างอิงที่อื่นให้ตรวจสอบให้ดีก่อนนะครับ ขอบคุณครับ)

สำหรับวันนี้ ต้องขอลาไปก่อน สวัสดีครับ NottDev :)

--

--

NottDev
NottDev

Written by NottDev

Your only limit is your mind.

Responses (2)