Output custom post shortcode. Help spot the error.

You’re resetting the value of $output each time you go through the loop:

foreach ($row as $post) {
        // etc.

        $output="<div class="col-md-6 event-item">"; // Here $output 

        // etc.
}

That $output assignment is resetting the value of $output to '<div class="col-md-6 event-item">', throwing out everything that had been appended to it.

You’re also returning $output at the end of the first loop:

foreach ($row as $post) {
    // etc.

    return $output;

}

That stops the entire function and returns the current value of $output, which will only be the first post at that point.

You’ll need to declare $output outside the loops (both of them), then only append from that point on, and return after the loops have finished:

function post_events($atts) {
    global $post;

    $args = array(
    'post_type'    => 'event',
    'post_status'  => 'publish',
    'orderby'      => 'date',
    'order'        => 'ASC',
    );

    $posts = get_posts($args);

    $posts_chunks = array_chunk($posts, 2);

    $output="";

    foreach ($posts_chunks as $row) {

        $output .= '<div class="row">';

        foreach ($row as $post) {
            setup_postdata($post);

            $output .= '<div class="col-md-6 event-item">';
            $output .= '<a href="' .get_the_permalink(). '">' .get_the_post_thumbnail(). '</a>';
            $output .= '<div class="event-item-text">';
            $output .= '<h3><a href="'.get_the_permalink(). '">' .get_the_title(). '</a></h3>';
            $output .= '<span class="event-date">' .get_the_date("Y-m-d"). '</span>';
            $output .= '<p>' .wp_trim_words( get_the_content(), 40, '...' ). '</p>';
            $output .= '</div>';
            $output .= '</div>';
        }

        $output .= '</div>';
    }

    return $output;
}
add_shortcode('post_events','post_events');