bzikarsky / gelf-php Goto Github PK
View Code? Open in Web Editor NEWA php implementation to send log-files to a gelf compatible backend like graylog
License: MIT License
A php implementation to send log-files to a gelf compatible backend like graylog
License: MIT License
Trivial... 😉
Hello! I have bug when i write log to GrayLog on the large load project. There is the bug:
Incomplete write: Only 0 of 358 written in /data/home/projects/payprocessing/classes/vendor/graylog2/gelf-php/src/Gelf/Transport/StreamSocketClient.php:212
Here is the message send to socket:
{
"version": "1.0",
"host": "pay-1.reserve.lan",
"short_message": "Redirect to https://www.platron.ru/payment_params.",
"full_message": "Redirect to https://www.platron.ru/payment_params.php?customer=5d44643437990b1774efb742ed1fb9a031005685\r\n(Process number: 84073)",
"level": 6,
"timestamp": 1484144247.0146,
"facility": "paypocessing",
"file": "Platron::payment"
}
I try to send id manual - and it's worked! So the problem in fwrite function. There is a notice in php documentation about fwrite function:
http://php.net/manual/en/function.fwrite.php
Some people say that when writing to a socket not all of the bytes requested to be written may be written. You may have to call fwrite again to write bytes that were not written the first time. (At least this is how the write() system call in UNIX works.)
I think you need to try fwrite_retry several times, before throw error, or, maybe, use some other function.
Write an Graylog2 compatible AMQP-transport. (Documentation)
Hello,
I just updated to the newest version an got some strange behavior because of this var_dump. Maybe it was forgotten to remove?
Kind regards
Matthias
Hello,
I'm switching from an old GELF lib to yours and I needed to do some adjustments regarding our needs.
I was wondering if is there is any interest of having this following method to be private:
private static function interpolate($message, array $context)
{
// build a replacement array with braces around the context keys
$replace = array();
foreach ($context as $key => $val) {
$replace['{' . $key . '}'] = $val;
}
// interpolate replacement values into the message and return
return strtr($message, $replace);
}
Instead of simply overriding the interpolate like that:
protected static function interpolate($message, array $context)
{
// Do some stufff
return parent::interpolate($message, $context);
}
I have to override the protected function initMessage($level, $message, array $context)
method :/
In some unittests a dummy class Gelf\Test\StringableClass
is used.
$toString = $this->getMock('dummyClass', array('__toString'));
$toString->method('__toString')->willReturn('toString');
require_once
for class in tests/bootstrap.php
Does it make sense that StreamSocketClient::buildSocket method throws exception if it can't connect? I mean if graylog server is down, nobody is catching this exception and my app is no available. Or one of solution would be instead of RuntimeException throw more specific exception that i could catch and handle it.
Hello,
Is anyone having issues with $message->setAdditional($key,$value) function. Here is the test script
<?php
require_once __DIR__ . '/vendor/gelf-php/gelf-php-master/vendor/autoload.php';
$transport = new Gelf\Transport\TcpTransport("<IP>, <PORT>);
$publisher = new Gelf\Publisher();
$publisher->addTransport($transport);
$message = new Gelf\Message();
$message->setShortMessage("It works in TCP!")
->setLevel(\Psr\Log\LogLevel::ALERT)
->setFullMessage("There was a foo in bar")
->setFacility("local8")
;
$message->setAdditional("IP", "10.4.13.45");
//var_dump($message);
$publisher->publish($message);
var_dump($publisher);
it works without setAdditional. And I do not see an error with setAdditional part of the script but nothing gets pushed to the graylog server.
Potential candidates:
Ruled out:
Currently, if some key has boolean value, is wrongly converted empty string and filtered out as empty value. #38 solves this, but it's somehow stuck and also solves an another problem.
30 secs is too much
maybe if HttpTransport accept another param $socketTimeout, pass to StreamSocketClient this could be used when initSocket() .. what do you think?
Requires analysis: Maybe it's even feasible to drop full 5.x support when 2.0 starts to become reality.
Helps with HHVM compatibility especially.
Might also prove useful in regards to PHP7 and changed SNI behavior
I'm trying to stream logs from a symfony 2 app to a graylog 2 server using the gelf format.
My monolog configuration looks as follows:
monolog: handlers: graylog: type: gelf publisher: hostname: my-graylog-server.com port: 12201 level: debug formatter: app.gelf_formatter
I'm getting a connection refused error when the graylog server is not available.
[2017-07-28 16:03:25] app.ERROR: Failed to write to socket: fwrite(): send of 153 bytes failed with errno=111 Connection refused (8) [] []
This is why I'm looking for how to set IgnoreErrorTransportWrapper option in my config.yml
Any help would be greatly appreciated!
In gelf-php 1.* the support for GELF 1.0 and 1.1 is hardcoded into Message:toArray.
2.0 should have better support for current and future versions of GELF in regards to architecture, message transformation and serialization.
Deprecated: SNI_server_name is deprecated in favor of peer_name in /var/www/vendor/graylog2/gelf-php/src/Gelf/Transport/StreamSocketClient.php on line 153
Deprecated: the 'CN_match' SSL context option is deprecated in favor of 'peer_name' in /var/www/vendor/graylog2/gelf-php/src/Gelf/Transport/StreamSocketClient.php on line 153
See #69
Hello,
I use php 5.6 on debian jessy.
I have a problem with TCPTransport.
I establish a connection to tha graylog2 server.
Everything is fine but when an error occurred, for example "Connection reset by peer" or "Broken pipe" - when I shutdown graylog2 infrastructure
fwrite returns with int(0), not boolean false value so "Failed to write to socket" exception will not be thrown because of $byteCount === false condition
Only the the following notice are generated:
Message: fwrite(): send of 166 bytes failed with errno=104 Connection reset by peer
Message: fwrite(): send of 166 bytes failed with errno=32 Broken pipe
Thx,
Cyr
It'd be a nice addition for HttpTransport
to have string-constructor like $transport = HttpTransport::fromUrl("http://logs.example.org:8080/gelf")
.
http://php.net/manual/function.parse-url.php
http
and https
should set their port automatically if not specifiedSslOptions
-object as a 2nd paramater (see #24)?/cc @steffkes
Would be nice to have an option to initialize HttpTransport / socket-client via Proxy.
Maybe like this :
$opts = array('http' => array('proxy' => 'tcp://127.0.0.1:8080', 'request_fulluri' => true));
$context = stream_context_create($opts);
Support for the HTTP input, see details at http://www.graylog2.org/resources/documentation/sending/gelfhttp
Hi
Thanks for great project!
Edit: I was wrong.
thx, Zoli
There is no validation if the additional keys fit the needed pattern [a-zA-Z_0-9.-].
The graylog2-server code has a regex for validating keys:
https://github.com/Graylog2/graylog2-server/search?q=VALID_KEY_CHARS&ref=cmdform
The GELF specification does not explicitly define it, but the example seems to rely on it:
http://graylog2.org/gelf#specs
Would be nice to the an option like setConnectionTimeout() in StreamSocketClient, to the set
stream_set_timeout()
ref. #40
See PR #87 which got merged without proper tests.
For an easy integration in Symfony2, Silex, etc. a monolog-handler should be the best way.
See:
Both of the following fail validation:
$logger->info(0);
and
$logger->info('0');
Why are these not valid log messages? Could the validator check for an empty string instead of a "falsey" value? Or are falsey values also forbidden by the graylog specification. Happy to try and submit a PR if required.
Hope you can help
Cheers
https://github.com/bzikarsky/gelf-php/blob/master/src/Gelf/Publisher.php#L69
$reason is undefined variable
We have our graylog instance sitting on a server that is not directly reachable from the Internet. In order to allow access to the HTTP GELF input, we defined a ProxyPass on a publicly visible server like so:
<Location /gelf/>
ProxyPass http://10.24.0.42:12201/gelf
ProxyPassReverse http://10.24.0.42:12201/gelf
</Location>
However, trying to establish a connection to graylog through this using the stream_socket_client as the StreamSocketClient does, always results in a 400 - Bad Request response by the Apache server:
RuntimeException: Graylog-Server didn't answer properly, expected 'HTTP/1.x 202 Accepted', response is 'HTTP/1.1 400 Bad Request Date: Thu, 22 Sep 2016 17:44:48 GMT Server: Apache/2.4.10 (Debian) Content-Length: 445 Connection: close Content-Type: text/html; charset=iso-8859-1' in /var/www/vendor/graylog2/gelf-php/src/Gelf/Transport/HttpTransport.php on line 189
Using curl, there's no issue at all:
kwisatz@mazer:~$ curl -i -XPOST https://graylog.domain.tld/gelf/ -p0 -d '{"short_message":"Hello there", "host":"example.org", "facility":"test", "_foo":"bar"}'
HTTP/1.1 202 Accepted
Date: Thu, 22 Sep 2016 17:15:07 GMT
Server: Apache/2.4.10 (Debian)
Content-Length: 0
Strict-Transport-Security: max-age=15768000
Connection: close
I've been trying to figure out if I had to configure mod_proxy differently for this to work but haven't really found any useful clues. I'm also not familiar with PHP's stream_socket_client and how this works on ssl:// socket connections.
It works just fine when not using SSL, but I'd really prefer not to send this data over the wire in plain-text.
I was hoping someone might have had the same issue already and solved it or someone might know how to configure mod_proxy with Apache?
Or, failure to figure this out, would it be possible to switch out the socketClient for a simple php-curl client?
Hi,
is there any way to set $connectTimeout for UdpTransport - which uses StreamSocketClient? Or maybe get access to the $socketClient so we could set it after initializing the UdpTransport?
Thanks,
Patryk
Defining transports as publishers is against the single-responsibility principle. We break BC with this change, so this has to be done in a major release.
Securing the GELF-endpoint behind authentication is a common usecase.
We probably do not need a constructor-argument though. An HTTP-Authentication header can be added at each request. It's not required on stream-connect. setAuthentication($user, $password)
should be sufficient.
Also only supporting baisc
-mode is okay initially, I think.
/cc @steffkes
Hi.
Why the methods «initMessage» and «initExceptionData» are private?
Now i'm writing data collector for https://github.com/maximebf/php-debugbar and my idea was to extend Gelf\Logger::log() method to collect Gelf\Message objects.
But «initMessage» method is private and i must copy&paste whole the content of this method only to reproduce the same object.
Is it a problem to make these methods protected?
A message MUST NOT consist of more than 128 chunks.
(c) https://www.graylog.org/resources/gelf/
But I see that your lib allowing up to 256 chunks. Please clarify which is correct.
Also I see logstash logs messages like this:
{
:timestamp=>"2015-10-14T13:38:01.927000+0300",
:message=>"Gelfd failed to parse a message skipping",
:exception=>#<Gelfd::TooManyChunksError: 130 greater than 128>,
:backtrace=>[
"/opt/logstash/vendor/bundle/jruby/1.9/gems/gelfd-0.2.0/lib/gelfd/chunked_parser.rb:40:in `parse_chunk'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/gelfd-0.2.0/lib/gelfd/chunked_parser.rb:8:in `parse'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/gelfd-0.2.0/lib/gelfd/parser.rb:10:in `parse'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-input-gelf-1.0.0/lib/logstash/inputs/gelf.rb:100:in `udp_listener'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-input-gelf-1.0.0/lib/logstash/inputs/gelf.rb:62:in `run'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-core-1.5.4-java/lib/logstash/pipeline.rb:177:in `inputworker'",
"/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-core-1.5.4-java/lib/logstash/pipeline.rb:171:in `start_input'"
],
:level=>:warn
}
Hi,
We have some issues with UDP transport and the 1.5.3 version (Incomplete write: Only 0 of XXX written
)
d98632d seems to correct it. Can you publish a tagged version with these changes ?
Thx a lot !
Currently the documentation is almost non existent. This should be changed.
SerializerInterface
which convert the message to a JsonSerializable structure$version
or getVersion
from Message
to the serializersThere is currently a condition in place to handle 1.0 and 1.1 message serialization. (
Line 279 in 30bdad7
When the GELF 2.0 spec is finalized, we need a better way to support multiple GELF standards.
Achieving this without breaking BC would be optimal. I'd rather not force GELF 2.0 users to a 2.0 upgrade, but if there is no way around so be it.
It seems that i hit a rare condition in Gelf\Message::setAdditional:
if the contextPrefix in the GelfMessageFormatter is an empty string - no prefixing - and the context is an associative array (like from a doctrine select statement):
array:7 [
"message" => "SELECT u0_.uuid AS uuid_0, u0_.username AS username_1, u0_.password AS password_2, u0_.roles AS roles_3, u0_.expired AS expired_4, u0_.locked AS locked_5, u0_.enabled AS enabled_6, u0_.credentials_expired AS credentials_expired_7 FROM "user" u0_ WHERE u0_.username = ?"
"context" => array:1 [
0 => "test"
]
"level" => 100
"level_name" => "DEBUG"
"channel" => "doctrine"
"datetime" => "1524690309.189944"
"extra" => []
]
the condition if(!$key)
will raise the RuntimeException (since !0 == true).
When the log()
$context
array contains non-string values (such as other arrays), a PHP Notice and PHP Warning are generated as the values are treated as if they will always be strings.
PSR-3 §1.3 states that the context array can contain anything, and the implementation "MUST NOT (...) raise any php error, warning or notice".
It seems that the notice arises from the interpolate()
method which is a copy of the FIG example code (shame!) and the warning from a specific implementation in Message::toArray()
which filters out non-strings.
If a non-string is encountered it would be good to modify it, such as running arrays through json_encode()
This library does not work when using against a Graylog2 v0.20 server, because the GELF specification has changed.
http://graylog2.org/gelf#specs
These fields are now deprecated: facility, line, file
Also, there seems to be a error when elasticsearch tries to index fields, that do not conform the the spec. For example, if "line" has the string value "null", the message will be dropped.
Tests for this library rely on PhpUnit 4.x (via composer.json) at max 5.x (usage of getMock()). It'd make sense in the long run (e.g. 2.x) to update + refactor to a newer supported PhpUnit version (>= 7) as a dependency.
Can this library GET/search messages from Graylog or do we need to go directly to elasticsearch?
I am using the GelfPublisher with UdpTransport in a website combination with Monolog to log to an logstash/elasticsearch server (ELK) and it is working great!
There is only one thing missing:
If a target server is not available the logging attempt terminates with a PHP error.
In this case I would prefer to have my website do its function as before, even if Gelf logging is not available.
This could be configured using an "ignore_error" option.
To avoid the need to do it in every transport it could be done in Publisher::publish if the foreach-loop is changed like this:
foreach ($this->transports as $transport) {
/* @var $transport TransportInterface */
try {
$transport->send($message);
} catch (ExceptionInterface $e) {
if (!$this->options['ignore_error']) {
throw new \RuntimeException("Error sending messages to transport", 0, $e);
}
}
}
Or, if it is preferred to enable this per transport it could go in AbstractTransport
See 1. in #69 (comment)
I use this package to send logs via monolog logger to Graylog2 server via UDP. I also use tunelling from my machine to this server, cause I cannot reach it directly. I've configured it with socat based on this example:
http://zarb.org/~gc/html/udp-in-ssh-tunneling.html
Basically, everything works as a charm when the tunel is created.
Although when the tunel is not there, then fwrite raises exception (what's more interesning: every 2nd time):
Exception raised 'Failed to write to socket: fwrite(): send of 361 bytes failed with errno=111 Connection refused (8) File: /var/www/paymentdating/vendor/graylog2/gelf-php/src/Gelf/Transport/StreamSocketClient.php, line# 225 (code 0)
so if my code looks like this:
$myLogger->alert('karamba'); $myLogger->alert('karamba'); $myLogger->alert('karamba'); $myLogger->alert('karamba');
The error is raised only for 2nd and 4th call.
I thought that because of UDP protocol there will be no exceptions. In the end I like them even, cause I can check the Graylog server is unreachable, although in most cases the script is gonna log only once and then unfortunately no exception is raised by fwrite.
Hello everyone, and thank you for your great tool :)
Here is the use case we are dealing with right now:
We have our php-application which uses monolog for logging, and the Gelf\Publisher as publisher for GelfHandler.
It is initialized like this, and it works fine:
$logger->pushHandler(new GelfHandler(new Gelf\Publisher(new Gelf\HttpTransport('graylogserver',12201)),Logger::INFO));
The problem is that http communications are not reliable. The server might be down or someone can change the settings or whatever, causing an exception to be thrown, crashing the application because of logging. I noticed that the socket gets created the moment we try to send our first log, but that feels a little too late.
May I suggest some possible solutions:
$logger->log()
call and still have a way to know of things going wrongIf you agree I can make a pull request for this :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.