Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
9f419030
Commit
9f419030
authored
Feb 25, 2020
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored tcp_client_sink
parent
64de8807
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
175 additions
and
86 deletions
+175
-86
include/spdlog/details/tcp_client.h
include/spdlog/details/tcp_client.h
+145
-0
include/spdlog/sinks/tcp_sink.h
include/spdlog/sinks/tcp_sink.h
+30
-86
No files found.
include/spdlog/details/tcp_client.h
0 → 100644
View file @
9f419030
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <string>
namespace
spdlog
{
namespace
details
{
class
tcp_client
{
int
socket_
=
-
1
;
public:
bool
is_connected
()
const
{
return
socket_
!=
-
1
;
}
void
close
()
{
if
(
is_connected
())
{
::
close
(
socket_
);
socket_
=
-
1
;
}
}
int
fd
()
const
{
return
socket_
;
}
~
tcp_client
()
{
close
();
}
// try to connect or throw on failure
void
connect
(
const
std
::
string
&
host
,
int
port
)
{
close
();
spdlog
::
info
(
"Connecting.."
);
struct
addrinfo
hints
{};
memset
(
&
hints
,
0
,
sizeof
(
struct
addrinfo
));
hints
.
ai_family
=
AF_INET
;
// IPv4
hints
.
ai_socktype
=
SOCK_STREAM
;
// TCP
hints
.
ai_flags
=
AI_NUMERICSERV
;
// port passed as as numeric value
hints
.
ai_protocol
=
0
;
auto
port_str
=
std
::
to_string
(
port
);
struct
addrinfo
*
addrinfo_result
;
auto
rv
=
::
getaddrinfo
(
host
.
c_str
(),
port_str
.
c_str
(),
&
hints
,
&
addrinfo_result
);
if
(
rv
!=
0
)
{
auto
msg
=
fmt
::
format
(
"::getaddrinfo failed: {}"
,
gai_strerror
(
rv
));
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
msg
));
}
// Try each address until we successfully connect(2).
int
last_errno
=
0
;
for
(
auto
*
rp
=
addrinfo_result
;
rp
!=
nullptr
;
rp
=
rp
->
ai_next
)
{
#ifdef SPDLOG_PREVENT_CHILD_FD
int
const
flags
=
SOCK_CLOEXEC
;
#else
int
const
flags
=
0
;
#endif
socket_
=
::
socket
(
rp
->
ai_family
,
rp
->
ai_socktype
|
flags
,
rp
->
ai_protocol
);
if
(
socket_
==
-
1
)
{
last_errno
=
errno
;
continue
;
}
rv
=
::
connect
(
socket_
,
rp
->
ai_addr
,
rp
->
ai_addrlen
);
if
(
rv
==
0
)
{
break
;
}
else
{
last_errno
=
errno
;
::
close
(
socket_
);
socket_
=
-
1
;
}
}
::
freeaddrinfo
(
addrinfo_result
);
if
(
socket_
==
-
1
)
{
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
"::connect failed"
,
last_errno
));
}
// set TCP_NODELAY
int
enable_flag
=
1
;
::
setsockopt
(
socket_
,
IPPROTO_TCP
,
TCP_NODELAY
,
(
char
*
)
&
enable_flag
,
sizeof
(
enable_flag
));
// prevent sigpipe on systems where MSG_NOSIGNAL is not available
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
::
setsockopt
(
socket_
,
SOL_SOCKET
,
SO_NOSIGPIPE
,
(
char
*
)
&
enable_flag
,
sizeof
(
enable_flag
));
#endif
#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
#error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
#endif
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void
send
(
const
char
*
data
,
size_t
n_bytes
)
{
size_t
bytes_sent
=
0
;
while
(
bytes_sent
<
n_bytes
)
{
#if defined(MSG_NOSIGNAL)
const
int
send_flags
=
MSG_NOSIGNAL
;
#else
const
int
send_flags
=
0
;
#endif
auto
write_result
=
::
send
(
socket_
,
data
+
bytes_sent
,
n_bytes
-
bytes_sent
,
send_flags
);
if
(
write_result
<
0
)
{
close
();
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
"write(2) failed"
,
errno
));
}
if
(
write_result
==
0
)
// (probably should not happen but in any case..)
{
break
;
}
bytes_sent
+=
static_cast
<
size_t
>
(
write_result
);
}
}
};
}
// namespace details
}
// namespace spdlog
\ No newline at end of file
include/spdlog/sinks/tcp_sink.h
View file @
9f419030
...
@@ -6,121 +6,65 @@
...
@@ -6,121 +6,65 @@
#include <spdlog/common.h>
#include <spdlog/common.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/tcp_client.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <mutex>
#include <mutex>
#include <string>
#include <string>
#include <chrono>
#include <functional>
#pragma once
#pragma once
// tcp client sink
// connect to remote address and send the formatted log.
// will attempt to reconnect if connection drops.
namespace
spdlog
{
namespace
spdlog
{
namespace
sinks
{
namespace
sinks
{
struct
tcp_sink_config
{
std
::
string
server_host
;
int
server_port
;
bool
lazy_connect
=
false
;
// connect on first log call instead of in construction
tcp_sink_config
(
std
::
string
host
,
int
port
)
:
server_host
{
std
::
move
(
host
)}
,
server_port
{
port
}
{}
};
template
<
typename
Mutex
>
template
<
typename
Mutex
>
class
tcp_sink
:
public
spdlog
::
sinks
::
base_sink
<
Mutex
>
class
tcp_sink
:
public
spdlog
::
sinks
::
base_sink
<
Mutex
>
{
{
public:
public:
// connect to tcp host/port or throw if failed
// connect to tcp host/port or throw if failed
// host can be hostname or ip address
// host can be hostname or ip address
tcp_sink
(
std
::
string
host
,
int
port
)
tcp_sink
(
tcp_sink_config
sink_config
)
:
config_
{
std
::
move
(
sink_config
)}
{
{
sock_
=
connect_to
(
host
,
port
);
if
(
!
config_
.
lazy_connect
)
}
~
tcp_sink
()
override
{
if
(
sock_
!=
-
1
)
{
{
::
close
(
sock_
);
this
->
client_
.
connect
(
config_
.
server_host
,
config_
.
server_port
);
}
}
}
}
~
tcp_sink
()
override
{}
protected:
protected:
void
sink_it_
(
const
spdlog
::
details
::
log_msg
&
msg
)
override
void
sink_it_
(
const
spdlog
::
details
::
log_msg
&
msg
)
override
{
{
spdlog
::
memory_buf_t
formatted
;
spdlog
::
memory_buf_t
formatted
;
spdlog
::
sinks
::
base_sink
<
Mutex
>::
formatter_
->
format
(
msg
,
formatted
);
spdlog
::
sinks
::
base_sink
<
Mutex
>::
formatter_
->
format
(
msg
,
formatted
);
size_t
bytes_sent
=
0
;
if
(
!
client_
.
is_connected
())
while
(
bytes_sent
<
formatted
.
size
())
{
{
auto
write_result
=
::
write
(
sock_
,
formatted
.
data
()
+
bytes_sent
,
formatted
.
size
()
-
bytes_sent
);
client_
.
connect
(
config_
.
server_host
,
config_
.
server_port
);
if
(
write_result
<
0
)
{
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
"write(2) failed"
,
errno
));
}
if
(
write_result
==
0
)
// (probably should not happen but in any case..)
{
break
;
}
bytes_sent
+=
static_cast
<
size_t
>
(
write_result
);
}
}
client_
.
send
(
formatted
.
data
(),
formatted
.
size
());
}
}
void
flush_
()
override
{}
void
flush_
()
override
{}
tcp_sink_config
config_
;
private:
details
::
tcp_client
client_
;
// try to connect and return socket fd or throw on failure
int
connect_to
(
const
std
::
string
&
host
,
int
port
)
{
struct
addrinfo
hints
;
memset
(
&
hints
,
0
,
sizeof
(
struct
addrinfo
));
hints
.
ai_family
=
AF_INET
;
// IPv4
hints
.
ai_socktype
=
SOCK_STREAM
;
// TCP
hints
.
ai_flags
=
AI_NUMERICSERV
;
// port passed as as numeric value
hints
.
ai_protocol
=
0
;
auto
port_str
=
std
::
to_string
(
port
);
struct
addrinfo
*
addrinfo_result
;
auto
rv
=
::
getaddrinfo
(
host
.
c_str
(),
port_str
.
c_str
(),
&
hints
,
&
addrinfo_result
);
if
(
rv
!=
0
)
{
auto
msg
=
fmt
::
format
(
"::getaddrinfo failed: {}"
,
gai_strerror
(
rv
));
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
msg
));
}
// Try each address until we successfully connect(2).
int
socket_rv
=
-
1
;
int
last_errno
=
0
;
for
(
auto
*
rp
=
addrinfo_result
;
rp
!=
nullptr
;
rp
=
rp
->
ai_next
)
{
#ifdef SPDLOG_PREVENT_CHILD_FD
int
const
flags
=
SOCK_CLOEXEC
;
#else
int
const
flags
=
0
;
#endif
socket_rv
=
::
socket
(
rp
->
ai_family
,
rp
->
ai_socktype
|
flags
,
rp
->
ai_protocol
);
if
(
socket_rv
==
-
1
)
{
last_errno
=
errno
;
continue
;
}
rv
=
::
connect
(
socket_rv
,
rp
->
ai_addr
,
rp
->
ai_addrlen
);
if
(
rv
==
0
)
{
break
;
}
else
{
last_errno
=
errno
;
::
close
(
socket_rv
);
socket_rv
=
-
1
;
}
}
::
freeaddrinfo
(
addrinfo_result
);
if
(
socket_rv
==
-
1
)
{
SPDLOG_THROW
(
spdlog
::
spdlog_ex
(
"::connect failed"
,
last_errno
));
}
return
socket_rv
;
}
private:
int
sock_
=
-
1
;
};
};
using
tcp_sink_mt
=
tcp_sink
<
std
::
mutex
>
;
using
tcp_sink_mt
=
tcp_sink
<
std
::
mutex
>
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment