54

I am trying to write some custom messages in my dmesg output. I tried:

logger "Hello" 

but this does not work. It exits without error, but no "Hello" appears int the output of:

dmesg 

I am using a Fedora 9, and it seems that there is no syslogd/klogd daemon running. However, all my kernel messages are succesfully written in the dmesg buffer.

Any idea?

8 Answers 8

46

dmesg displays what is in the kernel buffer, whereas logger is for syslogd. I think if you want to print things into the kernel buffer you will need to create a driver that uses the printk() kernel function. If you just want it in /var/log/messages, then with a "normal" setup I think what you have done with logger is already fine.

The most basic example of a driver with printk() would be:

hello.c:

#include <linux/module.h> #include <linux/kernel.h> int init_module(void) { printk(KERN_INFO "Hello world\n"); return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world\n"); } 

Makefile:

obj-m += hello.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 

Then:

$ make $ sudo insmod hello.ko $ dmesg | tail -n1 [7089996.746366] Hello world 

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 for more...

3
  • I got an error, since you have put spaces before the make -C ... in the Makefile instead of a Tab, so copying the above contents of the Makefile does not work - more here. I appear to be unable to add this in an edit... Thanks by the way, great answer. Commented Jul 11, 2014 at 18:17
  • syslog messages are now in /var/log/syslog and not anymore in /var/log/messages. (Changed for Ubuntu at least. Other distros might use the old location.) Commented Oct 11, 2020 at 22:32
  • Improved version of the driver he wrote can be found here: serverfault.com/questions/140354/… Commented Aug 22, 2023 at 19:10
138

You can, as root, write to /dev/kmsg to print to the kernel message buffer:

 fixnum:~# echo Some message > /dev/kmsg fixnum:~# dmesg | tail -n1 [28078118.692242] Some message 

I've tested this on my server and an embedded Linux device, and it works on both, so I'm just going to assume it works pretty much everywhere.

5
  • 1
    Interesting that in Ubuntu, this works as root but not with sudo. One actually needs to become root. Commented Jun 30, 2012 at 8:53
  • 22
    Actually, that's because the input redirection is handled by your shell, which is not running with elevated rights. Try running echo Some message | sudo tee /dev/kmesg as non-root. Commented Jul 4, 2012 at 11:56
  • 6
    That works. Thanks, interesting. By the way, its kmsg not kmesg but I also confuse with dmesg which has the e! Commented Jul 4, 2012 at 14:55
  • 5
    Much easier than compiling kernel module Commented Mar 3, 2014 at 9:22
  • 3
    For correct formatting in the syslog, be sure to add a priority (delimited with angles) and a tag (delimited by a colon). echo '<4>Foo: Message' | sudo tee /dev/kmsg Commented Jan 10, 2020 at 23:37
14

Based on Kyle's module above:

 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> static int pk_write(struct file *file, const char *buffer, unsigned long count, void *data) { char string[256]; count = count < 255 ? count : 255; if(copy_from_user(string, buffer, count)) return -EFAULT; string[count] = '\0'; printk(string); return count; } static int __init printk_init(void) { struct proc_dir_entry *pk_file; pk_file = create_proc_entry("printk", 0222, NULL); if(pk_file == NULL) return -ENOMEM; pk_file->write_proc = pk_write; pk_file->owner = THIS_MODULE; return 0; } static void __exit printk_cleanup(void) { remove_proc_entry("printk", NULL); } module_init(printk_init); module_exit(printk_cleanup); MODULE_LICENSE("GPL"); 

To do a printk from user space:

echo "Hello" > /proc/printk 
1
  • 1
    This works for Linux kernel < 3.10 only. See my answer for a newer alternative. Commented Nov 25, 2015 at 21:00
6

@Calandoa's answer no longer works for Kernel +3.10. Combined his code, and the example code I found here. Then improved on the code quality...

Code saved to printk_user.c

#include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> static ssize_t write_proc(struct file *filep, const char *buffer, size_t count, loff_t *offsetp) { char string[256]; count = count < 255 ? count : 255; if(copy_from_user(string, buffer, count) != 0) { return -EFAULT; } string[count] = '\0'; printk(string); return count; } static const struct file_operations proc_fops = { .owner = THIS_MODULE, .write = write_proc, }; static int proc_init(void) { struct proc_dir_entry *proc_file; proc_file = proc_create("printk_user", 0, NULL, &proc_fops); if(proc_file == NULL) { return -ENOMEM; } return 0; } static void proc_cleanup(void) { remove_proc_entry("printk_user", NULL); } MODULE_LICENSE("GPL"); module_init(proc_init); module_exit(proc_cleanup); 

Make using this Makefile

TARGET = printk_user obj-m := $(TARGET).o KERNEL_VERSION=$(shell uname -r) KDIR = /lib/modules/$(KERNEL_VERSION)/build PWD = $(shell pwd) printk: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean 

You'll need your current running kernel source code installed in order to make this. After you run make you will need to sudo insmod printk_user.ko to load the kernel module. The module creates /proc/printk_user, by default with permissions 444. If you need all users to access, modify with sudo chmod 666 /proc/printk_user

To do a printk from user space:

echo "Hello" > /proc/printk_user 

Sample output:

$ dmesg | tail [13291030.939275] printk_user: loading out-of-tree module taints kernel. [13291030.939862] printk_user: module verification failed: signature and/or required key missing - tainting kernel [13291103.728306] Hello 

edit: /proc/printk used to be for Kernel 3/4, but it appears the latest kernel has support for /proc/printk_user

3

Based off of Kyle's answer, here is a quick tutorial showing how to do just that.

3

Figured I'd go ahead and include a full blown example of something that people can just compile and run for those that aren't as skilled with C based off of @BuvinJ 's answer

#include <stdio.h> #include <string.h> #include <fcntl.h> // open function #include <unistd.h> // close function #include "sys/syscall.h" int main(); // Let's not worry about this for now void dmesg( const char *tag, const char *msg, const int len ) { const int TAG_LEN=3; char buffer[128]={0}; memcpy( &buffer[0], tag, TAG_LEN ); memcpy( &buffer[TAG_LEN], msg, len ); int fd_kmsg = open( "/dev/kmsg", O_WRONLY ); write( fd_kmsg, &buffer, TAG_LEN+len ); close( fd_kmsg ); } void dmesgWarn( const char *msg, const int len ){ dmesg( "<4>", msg, len ); } void dmesgInfo( const char *msg, const int len ){ dmesg( "<6>", msg, len ); } void dmesgDebug( const char *msg, const int len ){ dmesg( "<7>", msg, len ); } int main(int argc, char **argv) { int getmysize = strlen(argv[1]); printf("%d\n", getmysize); printf("To be written: %s\nSize of argument: %d\n", argv[1], getmysize); // dmesgWarn dmesgInfo or dmesgDebug dmesgDebug(argv[1], getmysize); }; 

To run save the above as kmsg.c then execute gcc kmsg.c -o kmsg and run as sudo ./kmsg "string you want to add to /dev/kmsg"

2

I just wanted some quick debugging messages in a daemon written by someone else in a cross complied kernel. I ran into a compile error trying to use printk, as <linux/module.h> could not be included. Rather then battle with that excessively (to do this the right way) I cheated and used the following lazy, but functional 5 minute workaround:

void dmesg( const char *tag, const char *msg, const int len ) { size_t taglen = strlen(tag); char buffer[taglen + len]; memcpy(&buffer[0], tag, taglen); memcpy(&buffer[taglen], msg, len); int fd_kmsg = open("/dev/kmsg", O_WRONLY); write(fd_kmsg, &buffer, TAG_LEN + len); close(fd_kmsg); } void dmesgWarn(const char *msg, const int len) { dmesg("<4>", msg, len); } void dmesgInfo(const char *msg, const int len) { dmesg("<6>", msg, len); } void dmesgDebug(const char *msg, const int len) { dmesg("<7>", msg, len); } 

UPDATE (Thanks @glglgl!)

A much simpler version could be like this:

void dmesg( const unsigned int tag, const char *msg) { size_t msglen = sprintf(NULL, "<%u>%s", tag, msg); char buffer[msglen + 1]; sprintf(buffer, "<%u>%s", tag, msg); // snprintf(buffer, sizeof(buffer), "<%u>%s", tag, msg); // would be safer, but here we make sure that everything works as it should. int fd_kmsg = open("/dev/kmsg", O_WRONLY); write(fd_kmsg, &buffer, msglen); close(fd_kmsg); } void dmesgWarn(const char *msg) { dmesg(4, msg); } void dmesgInfo(const char *msg) { dmesg(6, msg); } void dmesgDebug(const char *msg) { dmesg(7, msg); } 

It now just takes strings, integrates them in a message to be written to that file and writes it.

Now that we talk about it, it can be even much easier:

void dmesg( const unsigned int tag, const char *msg) { int fd_kmsg = open("/dev/kmsg", O_WRONLY); FILE * f_kmsg = fdopen(fd_kmsg, "w"); fprintf(f_kmsg, "<%u>%s", tag, msg); fclose(f_kmsg); // closes the underlying fd_kmsg as well } void dmesgWarn(const char *msg) { dmesg(4, msg); } void dmesgInfo(const char *msg) { dmesg(6, msg); } void dmesgDebug(const char *msg) { dmesg(7, msg); } 
6
  • size_t taglen = strlen(tag); char buffer[taglen + len]; memcpy( &buffer[0], tag, taglen); memcpy( &buffer[taglen], msg, len ); would do the trick as well. Commented Jul 26, 2022 at 7:42
  • Ok. I infer you are eliminating the need for the len argument? You could directly suggest an edit in that case, if you were so inclined. Commented Jul 26, 2022 at 13:30
  • Not for the len argument (that could be done as well), but for the constant TAG_LEN and the constant buffer[] size. Commented Jul 27, 2022 at 7:14
  • 1
    @glglgl Please suggest an "edit" directly. That is, you can modify my answer to improved it. Note that I wrote this was a "lazy, but functional 5 minute workaround". If you want to tweak this so it becomes a better answer, I certainly have no objection! Commented Jul 27, 2022 at 12:42
  • Ok, I just did so. Commented Jul 27, 2022 at 13:15
0

In case it can help someone dealing with this dmesg / kernel logs from userspace topic, but with interaction with upper level tools like journald/journalctl and loki/promtail.

As an addition to previous comment How to add message that will be read with dmesg?,

I'd recommend to use this form:

echo "<2>kernel: EXT4-fs (sda2): I/O error while writing superblock" > /dev/kmsg 

With <i> being severity level and kernel: specific tag, before any kernel "subsystem" additional tag.

Using kernel tag, journalctl won't report the log as issued by service "unknown". And in some cases it can also help to get your log properly ingested by tools like Loki/Promtail.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.