1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <lib/logger/logger.h> 6 7#include <fbl/string_buffer.h> 8#include <fuchsia/logger/c/fidl.h> 9#include <lib/fidl/cpp/message_buffer.h> 10#include <lib/zx/channel.h> 11#include <stdint.h> 12#include <syslog/logger.h> 13#include <syslog/wire_format.h> 14#include <zircon/processargs.h> 15#include <zircon/status.h> 16 17namespace logger { 18namespace { 19 20static fx_log_packet_t packet; 21 22} // namespace 23 24LoggerImpl::LoggerImpl(zx::channel channel, int out_fd) 25 : channel_(fbl::move(channel)), 26 fd_(out_fd), 27 wait_(this, channel_.get(), ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED), 28 socket_wait_(this) { 29} 30 31LoggerImpl::~LoggerImpl() { 32 fsync(fd_); 33} 34 35zx_status_t LoggerImpl::Begin(async_dispatcher_t* dispatcher) { 36 return wait_.Begin(dispatcher); 37} 38 39zx_status_t LoggerImpl::PrintLogMessage(const fx_log_packet_t* packet) { 40 fbl::StringBuffer<sizeof(fx_log_packet_t) + 100> buf; // should be enough to log message 41 buf.AppendPrintf("[%05ld.%06ld]", packet->metadata.time / 1000000000UL, (packet->metadata.time / 1000UL) % 1000000UL); 42 buf.AppendPrintf("[%ld]", packet->metadata.pid); 43 buf.AppendPrintf("[%ld]", packet->metadata.tid); 44 45 // print tags 46 size_t pos = 0; 47 buf.Append("["); 48 unsigned int tag_len = packet->data[pos]; 49 int i = 1; 50 while (tag_len > 0) { 51 if (i > FX_LOG_MAX_TAGS || tag_len > FX_LOG_MAX_TAG_LEN) { 52 return ZX_ERR_INVALID_ARGS; 53 } 54 if (i > 1) { 55 buf.Append(", "); 56 } 57 pos = pos + 1; 58 buf.Append(packet->data + pos, tag_len); 59 pos = pos + tag_len; 60 tag_len = packet->data[pos]; 61 i++; 62 } 63 buf.Append("]"); 64 65 auto severity = packet->metadata.severity; 66 switch (severity) { 67 case FX_LOG_INFO: 68 buf.Append(" INFO"); 69 break; 70 case FX_LOG_WARNING: 71 buf.Append(" WARNING"); 72 break; 73 case FX_LOG_ERROR: 74 buf.Append(" ERROR"); 75 break; 76 case FX_LOG_FATAL: 77 buf.Append(" FATAL"); 78 break; 79 default: 80 buf.AppendPrintf(" VLOG(%d)", -severity); 81 } 82 buf.Append(": "); 83 pos++; //point to log msg 84 buf.Append(packet->data + pos); 85 buf.Append("\n"); 86 87 ssize_t status = write(fd_, buf.data(), buf.size()); 88 if (status < 0) { 89 return ZX_ERR_IO; 90 } 91 return ZX_OK; 92} 93 94void LoggerImpl::OnLogMessage(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, 95 const zx_packet_signal_t* signal) { 96 if (status != ZX_OK) { 97 NotifyError(status); 98 return; 99 } 100 101 if (signal->observed & ZX_SOCKET_READABLE) { 102 memset(&packet, 0, sizeof(packet)); 103 status = socket_.read(0, &packet, sizeof(packet), nullptr); 104 if (status != ZX_OK) { 105 NotifyError(status); 106 return; 107 } 108 if (status != ZX_ERR_SHOULD_WAIT) { 109 // set last byte of packet to zero so that we don't overflow buffer while 110 // reading message. 111 packet.data[sizeof(packet.data) - 1] = 0; 112 status = PrintLogMessage(&packet); 113 if (status == ZX_ERR_INVALID_ARGS) { 114 NotifyError(status); 115 return; 116 } 117 } 118 status = wait->Begin(dispatcher); 119 if (status != ZX_OK) { 120 NotifyError(status); 121 } 122 return; 123 } 124 125 ZX_DEBUG_ASSERT(signal->observed & ZX_SOCKET_PEER_CLOSED); 126 NotifyError(ZX_ERR_PEER_CLOSED); 127} 128 129void LoggerImpl::OnHandleReady(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, 130 const zx_packet_signal_t* signal) { 131 if (status != ZX_OK) { 132 NotifyError(status); 133 return; 134 } 135 136 if (signal->observed & ZX_CHANNEL_READABLE) { 137 fidl::MessageBuffer buffer; 138 for (uint64_t i = 0; i < signal->count; i++) { 139 status = ReadAndDispatchMessage(&buffer, dispatcher); 140 if (status == ZX_ERR_SHOULD_WAIT) 141 break; 142 if (status != ZX_OK) { 143 NotifyError(status); 144 return; 145 } 146 } 147 status = wait->Begin(dispatcher); 148 if (status != ZX_OK) { 149 NotifyError(status); 150 } 151 return; 152 } 153 154 ZX_DEBUG_ASSERT(signal->observed & ZX_CHANNEL_PEER_CLOSED); 155 channel_.reset(); 156 if (!socket_) { 157 // if there is no socket, it doesn't make sense to keep running this 158 // instance. 159 NotifyError(ZX_ERR_PEER_CLOSED); 160 } 161} 162 163zx_status_t LoggerImpl::ReadAndDispatchMessage(fidl::MessageBuffer* buffer, async_dispatcher_t* dispatcher) { 164 fidl::Message message = buffer->CreateEmptyMessage(); 165 zx_status_t status = message.Read(channel_.get(), 0); 166 if (status != ZX_OK) 167 return status; 168 if (!message.has_header()) 169 return ZX_ERR_INVALID_ARGS; 170 switch (message.ordinal()) { 171 case fuchsia_logger_LogSinkConnectOrdinal: 172 return Connect(fbl::move(message), dispatcher); 173 default: 174 fprintf(stderr, "logger: error: Unknown message ordinal: %d\n", message.ordinal()); 175 return ZX_ERR_NOT_SUPPORTED; 176 } 177} 178 179zx_status_t LoggerImpl::Connect(fidl::Message message, async_dispatcher_t* dispatcher) { 180 if (socket_) { 181 return ZX_ERR_INVALID_ARGS; 182 } 183 const char* error_msg = nullptr; 184 zx_status_t status = message.Decode(&fuchsia_logger_LogSinkConnectRequestTable, &error_msg); 185 if (status != ZX_OK) { 186 fprintf(stderr, "logger: error: Connect: %s\n", error_msg); 187 return status; 188 } 189 auto* request = message.GetBytesAs<fuchsia_logger_LogSinkConnectRequest>(); 190 socket_.reset(request->socket); 191 socket_wait_.set_object(socket_.get()); 192 socket_wait_.set_trigger(ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED); 193 socket_wait_.Begin(dispatcher); 194 return ZX_OK; 195} 196 197void LoggerImpl::NotifyError(zx_status_t error) { 198 socket_wait_.Cancel(); 199 wait_.Cancel(); 200 channel_.reset(); 201 socket_.reset(); 202 if (error_handler_) 203 error_handler_(error); 204} 205 206} // namespace logger 207