java类org.apache.log4j.spi.ErrorCode的实例源码

SyslogTcpAppender.java 文件源码 项目:openrasp 阅读 25 收藏 0 点赞 0 评论 0
void connect(InetAddress address, int port) {
   if(this.address == null)
     return;
   try {
     // First, close the previous connection if any.
     cleanUp();
     stw = new SyslogTcpWriter(new Socket(address, port).getOutputStream(), syslogFacility);
   } catch(IOException e) {
     if (e instanceof InterruptedIOException) {
         Thread.currentThread().interrupt();
     }
     String msg = "Could not connect to remote log4j server at ["
+address.getHostName()+"].";
     if(reconnectionDelay > 0) {
       msg += " We will try again later.";
fireConnector(); // fire the connector thread
     } else {
         msg += " We are not retrying.";
         errorHandler.error(msg, e, ErrorCode.GENERIC_FAILURE);
     } 
     LogLog.error(msg);
   }
 }
StringWriterAppender.java 文件源码 项目:sparql-generate 阅读 18 收藏 0 点赞 0 评论 0
@Override
protected void append(LoggingEvent event) {
    if (this.layout == null) {
        errorHandler.error("No layout for appender " + name,
                null, ErrorCode.MISSING_LAYOUT);
        return;
    }
    String message = this.layout.format(event);
    Session session = sessions.get(event.getThreadName());
    if (session != null) {
        try {
            session.getBasicRemote().sendText(gson.toJson(new Response(message, "", false)));
        } catch (IOException ex) {
            System.err.println("IOException " + ex.getMessage());
        }
    } else {
        System.err.println("No session found for thread " + event.getThreadName());
    }
}
JMSAppender.java 文件源码 项目:cacheonix-core 阅读 21 收藏 0 点赞 0 评论 0
/**
    This method called by {@link AppenderSkeleton#doAppend} method to
    do most of the real appending work.  */
 public void append(LoggingEvent event) {
   if(!checkEntryConditions()) {
     return;
   }

   try {
     ObjectMessage msg = topicSession.createObjectMessage();
     if(locationInfo) {
event.getLocationInformation();
     }
     msg.setObject(event);
     topicPublisher.publish(msg);
   } catch(Exception e) {
     errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
         ErrorCode.GENERIC_FAILURE);
   }
 }
SocketAppender.java 文件源码 项目:cacheonix-core 阅读 28 收藏 0 点赞 0 评论 0
void connect(InetAddress address, int port) {
   if(this.address == null)
     return;
   try {
     // First, close the previous connection if any.
     cleanUp();
     oos = new ObjectOutputStream(new Socket(address, port).getOutputStream());
   } catch(IOException e) {

     String msg = "Could not connect to remote log4j server at ["
+address.getHostName()+"].";
     if(reconnectionDelay > 0) {
       msg += " We will try again later.";
fireConnector(); // fire the connector thread
     } else {
         msg += " We are not retrying.";
         errorHandler.error(msg, e, ErrorCode.GENERIC_FAILURE);
     } 
     LogLog.error(msg);
   }
 }
FileAppender.java 文件源码 项目:cacheonix-core 阅读 25 收藏 0 点赞 0 评论 0
/**
    If the value of <b>File</b> is not <code>null</code>, then {@link
    #setFile} is called with the values of <b>File</b>  and
    <b>Append</b> properties.

    @since 0.8.1 */
 public
 void activateOptions() {
   if(fileName != null) {
     try {
setFile(fileName, fileAppend, bufferedIO, bufferSize);
     }
     catch(java.io.IOException e) {
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
           e, ErrorCode.FILE_OPEN_FAILURE);
     }
   } else {
     //LogLog.error("File option not set for appender ["+name+"].");
     LogLog.warn("File option not set for appender ["+name+"].");
     LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
   }
 }
JMSQueueAppender.java 文件源码 项目:cacheonix-core 阅读 18 收藏 0 点赞 0 评论 0
/**
    * Overriding this method to activate the options for this class
    * i.e. Looking up the Connection factory ...
    */
   public void activateOptions() {

QueueConnectionFactory queueConnectionFactory;

try {

    Context ctx = getInitialContext();      
    queueConnectionFactory = (QueueConnectionFactory) ctx.lookup(queueConnectionFactoryBindingName);
    queueConnection = queueConnectionFactory.createQueueConnection();

    queueSession = queueConnection.createQueueSession(false,
                              Session.AUTO_ACKNOWLEDGE);

    Queue queue = (Queue) ctx.lookup(queueBindingName);
    queueSender = queueSession.createSender(queue);

    queueConnection.start();

    ctx.close();      

} catch(Exception e) {
    errorHandler.error("Error while activating options for appender named ["+name+
               "].", e, ErrorCode.GENERIC_FAILURE);
}
   }
JMSQueueAppender.java 文件源码 项目:cacheonix-core 阅读 20 收藏 0 点赞 0 评论 0
/**
    * This method called by {@link AppenderSkeleton#doAppend} method to
    * do most of the real appending work.  The LoggingEvent will be
    * be wrapped in an ObjectMessage to be put on the JMS queue.
    */
   public void append(LoggingEvent event) {

if(!checkEntryConditions()) {
    return;
}

try {

    ObjectMessage msg = queueSession.createObjectMessage();
    msg.setObject(event);
    queueSender.send(msg);

} catch(Exception e) {
    errorHandler.error("Could not send message in JMSQueueAppender ["+name+"].", e, 
               ErrorCode.GENERIC_FAILURE);
}
   }
EmailDailyRollingFileAppender.java 文件源码 项目:log4j-collector 阅读 26 收藏 0 点赞 0 评论 0
InternetAddress[] parseAddress(String addressStr) {
    try {
        InternetAddress[] as = InternetAddress.parse(addressStr, true);
        if (as != null && as.length > 0) {
            for (InternetAddress a : as) {
                a.setPersonal(a.getPersonal());
            }
        }
        return as;
    }catch (UnsupportedEncodingException e1){
        errorHandler.error("Could not parse address ["+addressStr+"].", e1,
                ErrorCode.ADDRESS_PARSE_FAILURE);
    } catch(AddressException e) {
        errorHandler.error("Could not parse address ["+addressStr+"].", e,
                ErrorCode.ADDRESS_PARSE_FAILURE);
    }
    return null;
}
EmailAppender.java 文件源码 项目:log4j-collector 阅读 23 收藏 0 点赞 0 评论 0
InternetAddress[] parseAddress(String addressStr) {
    try {
        InternetAddress[] as = InternetAddress.parse(addressStr, true);
        if (as != null && as.length > 0) {
            for (InternetAddress a : as) {
                a.setPersonal(a.getPersonal());
            }
        }
        return as;
    }catch (UnsupportedEncodingException e1){
        errorHandler.error("Could not parse address ["+addressStr+"].", e1,
                ErrorCode.ADDRESS_PARSE_FAILURE);
    } catch(AddressException e) {
        errorHandler.error("Could not parse address ["+addressStr+"].", e,
                ErrorCode.ADDRESS_PARSE_FAILURE);
    }
    return null;
}
JDBCAppender.java 文件源码 项目:daq-eclipse 阅读 31 收藏 0 点赞 0 评论 0
/**
 * loops through the buffer of LoggingEvents, gets a
 * sql string from getLogStatement() and sends it to execute().
 * Errors are sent to the errorHandler.
 *
 * If a statement fails the LoggingEvent stays in the buffer!
 */
public void flushBuffer() {
  //Do the actual logging
  removes.ensureCapacity(buffer.size());
  for (Iterator i = buffer.iterator(); i.hasNext();) {
    LoggingEvent logEvent = (LoggingEvent)i.next();
    try {
   String sql = getLogStatement(logEvent);
   execute(sql);
    }
    catch (SQLException e) {
   errorHandler.error("Failed to excute sql", e,
       ErrorCode.FLUSH_FAILURE);
    } finally {
      removes.add(logEvent);
    }
  }

  // remove from the buffer any events that were reported
  buffer.removeAll(removes);

  // clear the buffer of reported events
  removes.clear();
}
SocketAppender.java 文件源码 项目:daq-eclipse 阅读 29 收藏 0 点赞 0 评论 0
void connect(InetAddress address, int port) {
   if(this.address == null)
     return;
   try {
     // First, close the previous connection if any.
     cleanUp();
     oos = new ObjectOutputStream(new Socket(address, port).getOutputStream());
   } catch(IOException e) {
     if (e instanceof InterruptedIOException) {
         Thread.currentThread().interrupt();
     }
     String msg = "Could not connect to remote log4j server at ["
+address.getHostName()+"].";
     if(reconnectionDelay > 0) {
       msg += " We will try again later.";
fireConnector(); // fire the connector thread
     } else {
         msg += " We are not retrying.";
         errorHandler.error(msg, e, ErrorCode.GENERIC_FAILURE);
     } 
     LogLog.error(msg);
   }
 }
FileAppender.java 文件源码 项目:daq-eclipse 阅读 32 收藏 0 点赞 0 评论 0
/**
    If the value of <b>File</b> is not <code>null</code>, then {@link
    #setFile} is called with the values of <b>File</b>  and
    <b>Append</b> properties.

    @since 0.8.1 */
 public
 void activateOptions() {
   if(fileName != null) {
     try {
setFile(fileName, fileAppend, bufferedIO, bufferSize);
     }
     catch(java.io.IOException e) {
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
           e, ErrorCode.FILE_OPEN_FAILURE);
     }
   } else {
     //LogLog.error("File option not set for appender ["+name+"].");
     LogLog.warn("File option not set for appender ["+name+"].");
     LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
   }
 }
SimpleMongoDbAppender.java 文件源码 项目:log4jmongo 阅读 21 收藏 0 点赞 0 评论 0
/**
 * @see org.apache.log4j.AppenderSkeleton#activateOptions()
 */
@Override
public void activateOptions() {
    try {
        // Close previous connections if reactivating
        if (mongo != null) {
            close();
        }

        initialize();

    } catch (final Exception e) {
        errorHandler.error("Unexpected exception while initialising MongoDbAppender.", e,
                ErrorCode.GENERIC_FAILURE);
    }
}
SimpleMongoDbAppender.java 文件源码 项目:log4jmongo 阅读 20 收藏 0 点赞 0 评论 0
private List<Integer> getPortNums(final String[] ports) {
    final List<Integer> portNums = new ArrayList<Integer>();

    for (final String port : ports) {
        try {
            final Integer portNum = Integer.valueOf(port.trim());
            if (portNum < 0) {
                errorHandler.error(
                        "MongoDB appender port property can't contain a negative integer",
                        null, ErrorCode.ADDRESS_PARSE_FAILURE);
            } else {
                portNums.add(portNum);
            }
        } catch (final NumberFormatException e) {
            errorHandler.error(
                    "MongoDB appender can't parse a port property value into an integer", e,
                    ErrorCode.ADDRESS_PARSE_FAILURE);
        }

    }

    return portNums;
}
OrientDBAppender.java 文件源码 项目:log4j-database 阅读 18 收藏 0 点赞 0 评论 0
/**
 * Method that creates query for OrientDB from the JSONObject event in the queue
 * and executes it in the database
 * @see {@link DataBaseAppender}{@link #saveQueue()} 
 */
@Override
protected void saveQueue() {
    // TODO Auto-generated method stub
    if (queue.size() == 0)
        return;
    StringBuffer cmd = new StringBuffer("begin\n");
    for (Object obj : queue) {
        cmd.append("insert into " + table + " content " + ((JSONObject) obj).toString() + "\n");
    }
    cmd.append("commit\n");
    //System.out.println(cmd);
    try
    {
        database.command(new OCommandScript("sql", cmd.toString())).execute();
    }
    catch(Exception e){
        errorHandler.error("Unexpected exception while saving events", e,
                ErrorCode.GENERIC_FAILURE);
    }
}
JMSAppender.java 文件源码 项目:nabs 阅读 24 收藏 0 点赞 0 评论 0
/**
    This method called by {@link AppenderSkeleton#doAppend} method to
    do most of the real appending work.  */
 public void append(LoggingEvent event) {
   if(!checkEntryConditions()) {
     return;
   }

   try {
     ObjectMessage msg = topicSession.createObjectMessage();
     if(locationInfo) {
event.getLocationInformation();
     }
     msg.setObject(event);
     topicPublisher.publish(msg);
   } catch(Exception e) {
     errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
         ErrorCode.GENERIC_FAILURE);
   }
 }
FileAppender.java 文件源码 项目:nabs 阅读 27 收藏 0 点赞 0 评论 0
/**
    If the value of <b>File</b> is not <code>null</code>, then {@link
    #setFile} is called with the values of <b>File</b>  and
    <b>Append</b> properties.

    @since 0.8.1 */
 public
 void activateOptions() {
   if(fileName != null) {
     try {
setFile(fileName, fileAppend, bufferedIO, bufferSize);
     }
     catch(java.io.IOException e) {
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
           e, ErrorCode.FILE_OPEN_FAILURE);
     }
   } else {
     //LogLog.error("File option not set for appender ["+name+"].");
     LogLog.warn("File option not set for appender ["+name+"].");
     LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
   }
 }
JMSQueueAppender.java 文件源码 项目:nabs 阅读 19 收藏 0 点赞 0 评论 0
/**
    * Overriding this method to activate the options for this class
    * i.e. Looking up the Connection factory ...
    */
   public void activateOptions() {

QueueConnectionFactory queueConnectionFactory;

try {

    Context ctx = getInitialContext();      
    queueConnectionFactory = (QueueConnectionFactory) ctx.lookup(queueConnectionFactoryBindingName);
    queueConnection = queueConnectionFactory.createQueueConnection();

    queueSession = queueConnection.createQueueSession(false,
                              Session.AUTO_ACKNOWLEDGE);

    Queue queue = (Queue) ctx.lookup(queueBindingName);
    queueSender = queueSession.createSender(queue);

    queueConnection.start();

    ctx.close();      

} catch(Exception e) {
    errorHandler.error("Error while activating options for appender named ["+name+
               "].", e, ErrorCode.GENERIC_FAILURE);
}
   }
JMSQueueAppender.java 文件源码 项目:nabs 阅读 22 收藏 0 点赞 0 评论 0
/**
    * This method called by {@link AppenderSkeleton#doAppend} method to
    * do most of the real appending work.  The LoggingEvent will be
    * be wrapped in an ObjectMessage to be put on the JMS queue.
    */
   public void append(LoggingEvent event) {

if(!checkEntryConditions()) {
    return;
}

try {

    ObjectMessage msg = queueSession.createObjectMessage();
    msg.setObject(event);
    queueSender.send(msg);

} catch(Exception e) {
    errorHandler.error("Could not send message in JMSQueueAppender ["+name+"].", e, 
               ErrorCode.GENERIC_FAILURE);
}
   }
SettopLoggerFileAppender.java 文件源码 项目:cats 阅读 16 收藏 0 点赞 0 评论 0
/**
 * To a log event to the logger.
 * 
 * @param event
 *            LoggingEvent.
 */
@Override
public void append( LoggingEvent event )
{
    try
    {
        dirName = ( String ) event.getMDC( "SettopMac" );
        fileName = ( String ) event.getMDC( "LogFileName" );
        String logFileName = System.getProperty( "cats.home" ) + File.separator + dirName + File.separator
                + fileName;
        setFile( logFileName, fileAppend, bufferedIO, bufferSize );
        MDC.remove( "SettopMac" );
        MDC.remove( "LogFileName" );
    }
    catch ( IOException ie )
    {
        errorHandler.error( "Error occured while setting file for the log level " + event.getLevel(), ie,
                ErrorCode.FILE_OPEN_FAILURE );
    }
    super.append( event );
}
KinesisAppender.java 文件源码 项目:kinesis-log4j-appender 阅读 22 收藏 0 点赞 0 评论 0
/**
 * Closes this appender instance. Before exiting, the implementation tries to
 * flush out buffered log events within configured shutdownTimeout seconds. If
 * that doesn't finish within configured shutdownTimeout, it would drop all
 * the buffered log events.
 */
@Override
public void close() {
  ThreadPoolExecutor threadpool = (ThreadPoolExecutor) kinesisClient.getExecutorService();
  threadpool.shutdown();
  BlockingQueue<Runnable> taskQueue = threadpool.getQueue();
  int bufferSizeBeforeShutdown = threadpool.getQueue().size();
  boolean gracefulShutdown = true;
  try {
    gracefulShutdown = threadpool.awaitTermination(shutdownTimeout, TimeUnit.SECONDS);
  } catch (InterruptedException e) {
    // we are anyways cleaning up
  } finally {
    int bufferSizeAfterShutdown = taskQueue.size();
    if (!gracefulShutdown || bufferSizeAfterShutdown > 0) {
      String errorMsg = "Kinesis Log4J Appender (" + name + ") waited for " + shutdownTimeout
          + " seconds before terminating but could send only " + (bufferSizeAfterShutdown - bufferSizeBeforeShutdown)
          + " logevents, it failed to send " + bufferSizeAfterShutdown
          + " pending log events from it's processing queue";
      LOGGER.error(errorMsg);
      errorHandler.error(errorMsg, null, ErrorCode.WRITE_FAILURE);
    }
  }
  kinesisClient.shutdown();
}
KinesisAppender.java 文件源码 项目:kinesis-log4j-appender 阅读 18 收藏 0 点赞 0 评论 0
/**
 * This method is called whenever a logging happens via logger.log(..) API
 * calls. Implementation for this appender will take in log events instantly
 * as long as the buffer is not full (as per user configuration). This call
 * will block if internal buffer is full until internal threads create some
 * space by publishing some of the records.
 * 
 * If there is any error in parsing logevents, those logevents would be
 * dropped.
 */
@Override
public void append(LoggingEvent logEvent) {
  if (initializationFailed) {
    error("Check the configuration and whether the configured stream " + streamName
        + " exists and is active. Failed to initialize kinesis log4j appender: " + name);
    return;
  }
  try {
    String message = layout.format(logEvent);
    ByteBuffer data = ByteBuffer.wrap(message.getBytes(encoding));
    kinesisClient.putRecordAsync(new PutRecordRequest().withPartitionKey(UUID.randomUUID().toString())
        .withStreamName(streamName).withData(data), asyncCallHander);
  } catch (Exception e) {
    LOGGER.error("Failed to schedule log entry for publishing into Kinesis stream: " + streamName);
    errorHandler.error("Failed to schedule log entry for publishing into Kinesis stream: " + streamName, e,
        ErrorCode.WRITE_FAILURE, logEvent);
  }
}
Log4jFileAppender.java 文件源码 项目:tachyon-rdma 阅读 18 收藏 0 点赞 0 评论 0
/**
 * Called when a new log attempt is made, either due to server restart or rollover. The filename
 * is modified to identify the logging node in getNewFileName.
 */
@Override
public void activateOptions() {
  if (fileName != null) {
    if (!fileName.equals(mCurrentFileName)) {
      mOriginalFileName = fileName;
    } else {
      fileName = mOriginalFileName;
    }
    try {
      fileName = getNewLogFileName(fileName);
      setFile(fileName, fileAppend, bufferedIO, bufferSize);
    } catch (Exception e) {
      errorHandler.error("Error while activating log options", e, ErrorCode.FILE_OPEN_FAILURE);
    }
  }
}
SynchronizedCountingQuietWriter.java 文件源码 项目:logging 阅读 19 收藏 0 点赞 0 评论 0
public final void write(final String string) {
  if (string == null) {
    /*
     * Create an exception here so that a stack trace is available for
     * debugging purposes.
     */
    errorHandler.error("Attempt to write null - see Log4J bug list.",
        new RuntimeException("Fault in Log4J Layout"),
        ErrorCode.WRITE_FAILURE);
    return;
  }
  try {
    synchronized (lock) {
      final int length = string.length();
      out.write(string, 0, length);
      this.charCount += length;
    }
  } catch (IOException e) {
    if (e instanceof InterruptedIOException) {
      Thread.currentThread().interrupt();
    }
    errorHandler.error("Failed to write [" + string + "].", e,
        ErrorCode.WRITE_FAILURE);
  }
}
AppenderCalculatedValues.java 文件源码 项目:eclipse-telemetry 阅读 28 收藏 0 点赞 0 评论 0
public void activateOptions() {
if (fileName != null) {
    try {
        Date dNow = new Date( );
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy_MM_dd_hh_mm_ss");

        String dirName = "Log_" + ft.format(dNow);
        File dir = new File("log/" + dirName);
        dir.mkdir();

        fileName = dir.getPath() + "/calculated_values.log";
        setFile(fileName, fileAppend, bufferedIO, bufferSize);
    } catch (Exception e) {
        errorHandler.error("Error while activating log options", e,
                ErrorCode.FILE_OPEN_FAILURE);
    }
}
}
AppenderTelemetry.java 文件源码 项目:eclipse-telemetry 阅读 19 收藏 0 点赞 0 评论 0
public void activateOptions() {
if (fileName != null) {
    try {
        Date dNow = new Date( );
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy_MM_dd_hh_mm_ss");

        String dirName = "Log_" + ft.format(dNow);
        File dir = new File("log/" + dirName);
        dir.mkdir();

        fileName = dir.getPath() + "/telemetry.log";
        setFile(fileName, fileAppend, bufferedIO, bufferSize);
    } catch (Exception e) {
        errorHandler.error("Error while activating log options", e,
                ErrorCode.FILE_OPEN_FAILURE);
    }
}
}
AppenderDeviceErrors.java 文件源码 项目:eclipse-telemetry 阅读 18 收藏 0 点赞 0 评论 0
public void activateOptions() {
if (fileName != null) {
    try {
        Date dNow = new Date( );
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy_MM_dd_hh_mm_ss");

        String dirName = "Log_" + ft.format(dNow);
        File dir = new File("log/" + dirName);
        dir.mkdir();

        fileName = dir.getPath() + "/device_errors.log";
        setFile(fileName, fileAppend, bufferedIO, bufferSize);
    } catch (Exception e) {
        errorHandler.error("Error while activating log options", e,
                ErrorCode.FILE_OPEN_FAILURE);
    }
}
}
Log4jALAAppender.java 文件源码 项目:Log4jALA 阅读 21 收藏 0 点赞 0 评论 0
/**
 * @see org.apache.log4j.AppenderSkeleton#activateOptions()
 */
@Override
public void activateOptions() {
    try {
        // Close previous connections if reactivating
        if (httpDataCollector != null) {
            //httpDataCollector.close();
            close();
        }

        if (StringUtils.isEmpty(workspaceId)) {
            throw new Exception(
                    String.format("the Log4jALAAppender property workspaceId [%s] shouldn't be empty (log4j.xml)",
                            this.workspaceId));
        }
        if (StringUtils.isEmpty(sharedKey)) {
            throw new Exception(String.format(
                    "the Log4jALAAppender property sharedKey [%s] shouldn't be empty (log4j.xml)", this.sharedKey));
        }
        if (StringUtils.isEmpty(logType)) {
            throw new Exception(String.format(
                    "the Log4jALAAppender property logType [%s] shouldn't be empty (log4j.xml)", this.logType));
        }

        serializer = new LoggingEventSerializer();

        httpDataCollector = new HTTPDataCollector(this.workspaceId, this.sharedKey,
                this.threadPoolSize <= 0 ? 1000 : this.threadPoolSize, this, this.proxyHost, this.proxyPort);

    } catch (Exception e) {
        errorHandler.error("Unexpected exception while initialising HTTPDataCollector.", e,
                ErrorCode.GENERIC_FAILURE);
    }
}
JDBCLog.java 文件源码 项目:MultimediaDesktop 阅读 19 收藏 0 点赞 0 评论 0
public void close() {
    flushBuffer();

    try {
        if (connection != null && !connection.isClosed())
            connection.close();
    } catch (SQLException e) {
        errorHandler.error("Error closing connection", e,
                ErrorCode.GENERIC_FAILURE);
    }
    this.closed = true;
}
JDBCLog.java 文件源码 项目:MultimediaDesktop 阅读 20 收藏 0 点赞 0 评论 0
public void setDriver(String driverClass) {
    try {
        Class.forName(driverClass);
    } catch (Exception e) {
        errorHandler.error("Failed to load driver", e,
                ErrorCode.GENERIC_FAILURE);
    }
}


问题


面经


文章

微信
公众号

扫码关注公众号