How to Write an C/C++ Application That Writes to a /Var/Log/Myapp Directory

How to write an C/C++ application that writes to a /var/log/myapp directory?

No, no no no. No suid for such stuff. These logs are managed by a process known as "syslog" and there is an API to send messages to this logger:

   void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);

Or you can type 'man syslog' on the command line and get all the info :-)

Update: you will need permissions to edit syslog's configuration file to send message to a separate log file, otherwise they will end up in the default location (probably /var/log/syslog).

How to add log files and folder in var/log/my-app-dir on Linux with NLog

The NLog InternalLogger is mostly for diagnostics and troubleshooting, so the logic for dynamic control of logging path is rather limited for simplicity and reduced chance of errors.

You can right now use the following keywords:

  • ${basedir}
  • ${processdir}
  • ${currentdir}
  • ${tempdir}
  • %appdata%

See also: https://github.com/NLog/NLog/wiki/Internal-Logging

In your case then I would probably consider perform a token-search-replace on deployment of NLog.config (Make a search for XML-transformations on deployment).

Alternative just assign the application-name at startup like this:

var logDir = "var/log/my-app";
NLog.GlobalDiagnosticsContext.Set("LogDir", logDir);
NLog.Common.InternalLogger.LogFile = System.IO.Path.Combine(logDir, "internal.txt");

With this NLog.config:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwConfigExceptions="true"
internalLogLevel="info">

<targets>
<target xsi:type="File" name="allfile" fileName="${gdc:LogDir}/nlog-all.log" />
<target xsi:type="File" name="ownfile" fileName="${gdc:LogDir}/nlog-own.log" />
</targets>

<!-- rules to map from logger name to target -->
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile" />

<!--Skip non-critical Microsoft logs and so log only own logs-->
<logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole -->

<logger name="*" minlevel="Trace" writeTo="ownfile" />
</rules>
</nlog>

c# Best Method to create a log file

I would not use third party libraries, I would log to an xml file.

This is a code sample that do logging to a xml file from different threads:

private static readonly object Locker = new object();
private static XmlDocument _doc = new XmlDocument();

static void Main(string[] args)
{
if (File.Exists("logs.txt"))
_doc.Load("logs.txt");
else
{
var root = _doc.CreateElement("hosts");
_doc.AppendChild(root);
}

for (int i = 0; i < 100; i++)
{
new Thread(new ThreadStart(DoSomeWork)).Start();
}
}

static void DoSomeWork()
{
/*
* Here you will build log messages
*/
Log("192.168.1.15", "alive");
}

static void Log(string hostname, string state)
{
lock (Locker)
{
var el = (XmlElement)_doc.DocumentElement.AppendChild(_doc.CreateElement("host"));
el.SetAttribute("Hostname", hostname);
el.AppendChild(_doc.CreateElement("State")).InnerText = state;
_doc.Save("logs.txt");
}
}

Best practice to write logs in /var/log from a python script?

If syslogd is running on your box, you can try to use SysLogHandler to avoid issue with folder permissions
(https://docs.python.org/2/library/logging.handlers.html#sysloghandler).

To specify your category, you need to set facility parameter to desired, for example LOG_LOCAL5. In this case, it will correspond to local5.* category of syslogd.

As you specify facility as handler parameter, but not file name, you need to adjust syslog configuration to say syslogd to write log records to particular file. In FreeBSD, syslog conf file is /etc/syslog.conf (syslog.conf(5)).

Also you can add syslog mapping like . to /var/log/all.log to handle all logs from all syslog producers. It's helpful to determine if logging works and what is your application category, if there is a doubt.

For rsyslogd, it's possible to get more informations here: How to configure rsyslog for use with SysLogHandler logging class?

How to configure syslog so that an applications log goes to a specific file

According to the syslog(3) manpage, the first parameter for openlog() sets a prefix for log messages, not a filename.
You can use a facility like LOG_LOCAL0 to flag your output and then configure syslogd using /etc/syslog.conf to send those logs to the file of your desire.

How to allow Tomcat WAR app to write in folder

Let's start with: chmod 777 is great for testing, but absolutely unfit for the real world and you shouldn't get used to this setting. Rather set the owner/group correctly, before you give world write permissions.

Edit: A similar question just came up on the Tomcat mailing list, and Emmanuel Bourg pointed out that Debian Tomcat is sandboxed by systemd. Read your /usr/share/doc/tomcat9/README.Debian which contains this paragraph:

Tomcat is sandboxed by systemd and only has write access to the
following directories:

  • /var/lib/tomcat9/conf/Catalina (actually /etc/tomcat9/Catalina)
  • /var/lib/tomcat9/logs (actually /var/log/tomcat9)
  • /var/lib/tomcat9/webapps
  • /var/lib/tomcat9/work (actually /var/cache/tomcat9)

If write access to other directories is required the service settings
have to be overridden. This is done by creating an override.conf file
in /etc/systemd/system/tomcat9.service.d/ containing:

[Service]

ReadWritePaths=/path/to/the/directory/

The service has to be restarted afterward with:

  systemctl daemon-reload
systemctl restart tomcat9

Edit 2022: Note that these are the 2019 paths - validate the file locations for later versions. From the comments to this answer (thank you to V H and Ng Sek Long) here are some updates:

In current Ubuntu file is here: sudo vi /etc/systemd/system/multi-user.target.wants/tomcat9.service – V H Feb 26, 2022 at 19:55

Mine (Ubuntu 20) is installed here /lib/systemd/system/tomcat9.service smh everybody use a different path. – Ng Sek Long Mar 28, 2022 at 8:36

End of edit, continuing with the passage that didn't solve OP's problem, but should stay in:

If - all things tested - Tomcat should have write access to that directory, but doesn't have it, the error message points me to an assumption: Could it be that

  • Tomcat is running as root?
  • The directory is mounted through NFS?

The default configuration for NFS is that root has no permissions whatsoever on that external filesystem (or was it no write-permission? this is ancient historical memory - look up "NFS root squash" to get the full story)

If this is a condition that matches what you are running, you should stop running Tomcat as root, and rather run it as an unprivileged user. Then you can set the permissions on the directory in question to be writeable by your tomcat-user, and readable by nginx, and you're done.

Running Tomcat as root is a recipe for disaster: You don't want a process that's available from the internet to run as root.

If these conditions don't meet your configuration: Elaborate on the configuration. I'd still stand by this description for others who might find this question/answer later.



Related Topics



Leave a reply



Submit