Reputation: 1
I am trying to display the output of /var/log/messages or similar (../secure for instance) in a webpage that I access through a webserver on the same host.
Should I use bash to tail -f >> the messages file to a new output file and display that text file in the html page, or is there a better way to do this?
Thanks! idiglivemusic
Upvotes: 0
Views: 2791
Reputation: 1
<!DOCTYPE html>
<html>
<head>
<title>toyLogs</title>
</head>
<body>
<div><p><?php include('/var/www/html/accesslog.txt'); ?></p></div>
</body>
</html>
Upvotes: -1
Reputation: 21955
Method 1
In one of your base directories, create a symbolic link
ln -s /var/log/messages messages
If the directory belonged to say, test.web
, access the log with
unmesh
http://test.web/messages
Method 2
If you're looking for a php
script then, first create the link as mentioned in method 1. Then, create a new file, say, readlog.php
in the base directory of test.web
with the below content :
<?php
readfile(“$DOCUMENT_ROOT/messages”);
?>
Access the readlog.php
like :
http://test.web/readlog.php
Requirement:
Read
access should be enabled for all users for /var/log/messages
.
Note:
Setting read
option for /var/log/messages
for the whole world is NOT a good idea.
Upvotes: 0
Reputation: 21492
If you're looking for a way to display actual file contents online without the need to reload the page, then you should setup a WebSocket server.
You can build a WebSocket server using a framework such as phpDaemon, ReactPHP, Ratchet, icicle, or implement your own server with the help of PHP extensions wrapping asynchronous libraries: event, ev, or similar.
I've chosen a random framework from the list above: Ratchet. Ratchet is based on ReactPHP. ReactPHP chooses a backend for the event loop from the following list:
- libevent
extension,
- libev
extension,
- event
extension,
- or an internal class based on the built-in stream_select()
function.
As a maintainer of the event
extension, I've chosen event
.
I've written a "quick" example just to give you idea of how it might be implemented. You'll most likely have to work out your own version, maybe using different tools. But the code should give you an impulse.
src/MyApp/Server.php
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Server implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
printf("Connection %d sending '%s' to %d other connection%s\n",
$from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
public function broadcast($msg) {
foreach ($this->clients as $client) {
$client->send($msg);
}
}
}
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Server;
require __DIR__ . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
$my_app_server = new Server()
)
),
9989
);
$loop = $server->loop;
$filename = '/var/log/messages';
$loop->addPeriodicTimer(5, function ()
use ($filename, $my_app_server)
{
static $stat_info;
if ($stat_info == null) {
clearstatcache(true, $filename);
$stat_info = stat($filename);
}
clearstatcache(true, $filename);
$st = stat($filename);
$size_diff = $st['size'] - $stat_info['size'];
echo "Diff = $size_diff bytes\n";
if ($size_diff > 0) {
$offset = $stat_info['size'];
$bytes = $size_diff;
} elseif ($size_diff < 0) {
// The file is likely truncated by `logrotate` or similar utility
$offset = 0;
$bytes = $st['size'];
} else {
$bytes = 0;
}
$stat_info = $st;
if ($bytes) {
if (! $fp = fopen($filename, 'r')) {
fprintf(STDERR, "Failed to open file $filename\n");
return;
}
if ($offset > 0) {
fseek($fp, $offset);
}
if ($msg = fread($fp, $bytes)) {
$my_app_server->broadcast($msg);
}
fclose($fp);
}
}
);
$server->run();
test.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Test</title>
</head>
<body>
<script>
var conn = new WebSocket('ws://localhost:9989');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log("Msg from server", e.data);
};
</script>
</body>
</html>
I'll skip the steps required to setup a basic test environment using Composer. Assuming you have successfully configured the test environment for the files above, you'll be able to run the server with the following command:
php server.php
Check, if the user has permissions to read /var/log/messages
. On my system only root
can read the file. So you might need to run the above-mentioned command with sudo
(root permissions).
Now you can open test.html
in a browser and look at the console output. Then trigger some event which is normally logged to the messages file. For instance, you can invoke sudo
with a wrong password. The server should detect the changes within interval of 5 seconds, then send it to the WebSocket clients.
Upvotes: 2
Reputation: 19982
Make sure that your html-server has rights to access the page and read the page (with something like cat
, tail
, grep
).
In <html>
put the output between <pre>
and </pre>
.
Upvotes: 0
Reputation: 361
If you're using tail -f, that means that you'll be continuously getting data from the file while it grows as the command runs. You can use cat or tail -n. Also, of course, you can access files directly by creating a symbolic or hard link to them (ln source-file link-file, ln -s source-file link-file) - but make sure, that your web-server has enough rights to access them.
Upvotes: 1